PHP-FPM容器
Nginx容器
在这篇博客文章中,我将概述我从上述方法1到方法2的过程,最后用介绍如何使用新定制Nginx Docker镜像的解决方案来结束这篇博客。
我已经将这个镜像开源GitHub[2],所以如果这刚好是您经常遇到的问题,请随时查看。
为什么是Nginx?
如果您想将Nginx容器连接到PHP-FPM后端,则需要将该后端的DNS记录添加到您的Nginx配置中。
例如,如果PHP-FPM容器作为名为php-fpm-api的容器运行,那么您的Nginx配置文件应该这样写:
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;
}
如果你只服务一个PHP-FPM容器应用,在你的Nginx容器的配置文件中硬编码对应的名字是可以的。但是,如我上面提到的,每个PHP服务都需要一个对应的Nginx容器,我们就需要运行多个Nginx容器。创建一个新的Nginx镜像(我们后面必须维护和升级)将是一件痛苦的事情,因为即使管理一堆不同的卷,对于更改单个变量名称似乎也有很多工作要做。
第一个解决方案:使用Docker文档里提到的方法envsubst
vhost.conf
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 ${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;
}
}
我的vhost.conf文件用到了好几个Nginx内置的环境变量,结果当我运行Docker文档里提到的如下命令行时,提示错误:$uri和fastcgi_script_name未定义。
shell
/bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
这些变量通常由Nginx本身传入[5],所以不容易搞清楚他们是什么和怎么进行参数传递的,而且这会影响容器的动态可配置性。
Martin的镜像有点不太一样,因为它要求特定的文件目录结构。我先在Dockerfile中添加了:
FROM martin/nginx
接下来,我添加了app/空目录,只包含一个vhost.conf文件的conf/目录。
vhost.conf
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;
}
}
这个跟我原始的配置文件差不多,只修改了一行:fastcgi_pass $ENV{"NGINX_HOST"}:9000;。现在当我想要启动一个Nginx容器和一个叫php-fpm-api的PHP容器的时候,我可以先编译一个新的镜像,然后在它运行的时候传递给它对应的环境变量:
shell
docker build -t shiphp/nginx-env:test .
docker run -it --rm -e NGINX_HOST=php-fpm-api shiphp/nginx-env:test
成功了!但是,这个方法有两个问题困扰着我:
基础镜像版本陈旧,两年多没更新了。这可能会造成安全和性能风险。
要求一个app的空目录似乎没啥必要,再加上我的文件放在不同的目录。
最终解决方案
shell
# Pull down the latest from Docker Hub
docker pull shiphp/nginx-env:latest
# Run a PHP container named "php-fpm-api"
docker run --name php-fpm-api -v $(pwd):/var/www php:fpm
# Start this NGinx container linked to the PHP-FPM container
docker run --link php-fpm-api -e NGINX_HOST=php-fpm-api shiphp/nginx-env
如果你想自定义这个镜像,添加你自己的文件或者Nginx配置文件,只需要像下面这样扩展你的Dockerfile:
FROM shiphp/nginx-env
ONBUILD ADD <PATH_TO_YOUR_CONFIGS> /etc/nginx/conf.d/
现在我所有的PHP-FPM容器都使用单个Nginx镜像的实例,当我需要升级Nginx、修改权限或者配置一些东西的时候,这让我的生活变得简单多了。
所有的代码都放在GitHub[2]上面了。如果您发现任何问题或想要提出改进建议,请随时创建issue。如果您对这个问题或Docker相关的任何问题,可以在Twitter[7]上找我一起讨论。
相关链接:
https://www.shiphp.com/blog/2017/php-web-app-in-docker
https://github.com/shiphp/nginx-env
https://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/
https://docs.docker.com/samples/library/nginx/#using-environment-variables-in-nginx-configuration
http://nginx.org/en/docs/varindex.html
https://hub.docker.com/r/martin/nginx/
https://twitter.com/shiphpnow
6月22日正式上课,点击阅读原文链接即可报名。