最近, 原文作者一直在使用 Docker 容器来开发 PHP 微服务套件. 一个问题是 PHP 应用已经搭建, 可以和 PHP-FPM 和 Nginx(取代了 简单的 Apche/PHP 环境 https://www.shiphp.com/blog/2017/php-web-app-in-docker)一起工作, 因此每个 PHP 微服务需要两个容器(以及两个 Docker 镜像): 一个 PHP-FPM 容器和一个 NGinx 容器.
这个应用运行了 6 个以上的服务, 如果做个乘法, 在开发和生产之间会有约 30 个容器. 作者决定构建一个单独的 NGinx Docker 镜像, 它可以使用 PHP-FPM 的主机名作为环境变量并运行单独的配置文件, 而没有为每个容器构建单独的 NGinx 镜像.
在本文中, 原文作者简要说明从上图中的方法 1 到方法 2 的转换, 最后采用的方案中采用了一种新的定制 Docker 镜像. 该镜像的代码是开源的, 如果读者碰到类似问题, 可以随时签出该部分代码.
为什么用 NGinx?
NGinx 和 PHP-FPM 配合使用 能使 PHP 应用的性能更好 https://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/ , 但不好的是和 PHP Apache 镜像不同, PHP-FPM Docker 镜像 https://hub.docker.com/_/php/ 缺省并没有和 NGinx 进行绑定. 如果需要通过 NGinx 容器和 PHP-FPM 连接, 需要在 NGind 配置里为该后端增加 DNS 记录. 比如, 如果名为 php-fpm-api 的 PHP-FPM 容器正在运行, NGinx 配置文件应该包含下面部分:
- location ~ \.php$ {
- fastcgi_split_path_info ^(.+\.php)(/.+)$;
- # This line passes requests through to the PHP-FPM container
- fastcgi_pass php-fpm-api:9000;
- fastcgi_index index.php;
- include fastcgi_params;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- fastcgi_param PATH_INFO $fastcgi_path_info;
- }
如果只服务于单独的 NGinx 容器, NGinx 配置中容器名字写死还可以接受, 但如上所述, 需要允许多个 NGinx 容器, 每个对应于一个 PHP 服务. 创建一个新的 NGinx 镜像 (以后需要进行维护和升级) 会有些痛苦, 即使管理一批不同的数据卷, 仅仅改变变量名看起来也有很多工作.
第一种方案: 使用 Docker 文档中的方法
最初, 作者认为这会很简单. Docker 文档中有少许的几个章节讨论如何使用 envsubst 来完成该工作 https://docs.docker.com/samples/library/nginx/#using-environment-variables-in-nginx-configuration , 但不幸的是, 在其 NGinx 配置文件中, 这种方法不奏效.
- vhosts.conf
- server {
- listen 80;
- index index.php index.html;
- root /var/www/public;
- client_max_body_size 32M;
- location / {
- try_files $uri /index.php?$args;
- }
- location ~ \.php$ {
- fastcgi_split_path_info ^(.+\.php)(/.+)$;
- fastcgi_pass ${NGINX_HOST}:9000;
- fastcgi_index index.php;
- include fastcgi_params;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- fastcgi_param PATH_INFO $fastcgi_path_info;
- }
- }
该 vhosts.conf 文件使用了 NGinx 内置变量 http://nginx.org/en/docs/varindex.html , 因此当依照文档运行 Docker 命令(
/bin/bash -c "envsubst </etc/nginx/conf.d/mysite.template> /etc/nginx/conf.d/default.conf && nginx -g'daemon off;'"
)时, 得到错误提示 $ uri 和
$fastcgi_script_name
没有定义. 这些变量通常通过 NGinx 传入, 因此不能简单的识别出他们是什么并传给自身, 而且这使容器的动态性变差.
用另一个 Docker 镜像来救急, 差点成功
接下来, 作者开始研究不同的 NGinx 镜像. 找到的两个, 但它们都在随后的几年中都没有任何更新. 作者开始使用 https://hub.docker.com/r/martin/nginx/ , 试图找到可以工作的原型.
- server {
- listen 80;
- index index.php index.html;
- root /var/www/public;
- client_max_body_size 32M;
- location / {
- try_files $uri /index.php?$args;
- }
- location ~ \.php$ {
- fastcgi_split_path_info ^(.+\.php)(/.+)$;
- fastcgi_pass $ENV{"NGINX_HOST"}:9000;
- fastcgi_index index.php;
- include fastcgi_params;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- fastcgi_param PATH_INFO $fastcgi_path_info;
- }
- }
- docker build -t shiphp/nginx-env:test .
- docker run -it --rm -e NGINX_HOST=php-fpm-api shiphp/nginx-env:test
- # 从 Docker Hub 得到最新版本
- docker pull shiphp/nginx-env:latest
- # 运行名为 "php-fpm-api" 的 PHP 容器
- docker run --name php-fpm-api -v $(pwd):/var/www php:fpm
- # 允许链接到 PHP-FPM 容器的 NGinx 容器
- docker run --link php-fpm-api -e NGINX_HOST=php-fpm-api shiphp/nginx-env
- FROM shiphp/nginx-env
- ONBUILD ADD <PATH_TO_YOUR_CONFIGS> /etc/nginx/conf.d/
- ...
来源: http://www.tuicool.com/articles/e2UvE33