如何正确链接 php-fpm 和 Nginx Docker 容器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29905953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to correctly link php-fpm and Nginx Docker containers?
提问by Victor Bocharsky
I am trying to link 2 separate containers:
我正在尝试链接 2 个单独的容器:
The problem is that php scripts do not work. Perhaps the php-fpm configuration is incorrect.
Here is the source code, which is in my repository. Here is the file docker-compose.yml
:
问题是 php 脚本不起作用。也许 php-fpm 配置不正确。这是源代码,它在我的存储库中。这是文件docker-compose.yml
:
nginx:
build: .
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www/test/
links:
- fpm
fpm:
image: php:fpm
ports:
- "9000:9000"
and Dockerfile
which I used to build a custom image based on the nginx one:
和Dockerfile
我使用了基于nginx的一个建立一个自定义图像:
FROM nginx
# Change Nginx config here...
RUN rm /etc/nginx/conf.d/default.conf
ADD ./default.conf /etc/nginx/conf.d/
Lastly, here is my custom Nginx virtual host config:
最后,这是我的自定义 Nginx 虚拟主机配置:
server {
listen 80;
server_name localhost;
root /var/www/test;
error_log /var/log/nginx/localhost.error.log;
access_log /var/log/nginx/localhost.access.log;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/.+\.php(/|$) {
fastcgi_pass 192.168.59.103:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
Could anybody help me configure these containers correctly to execute php scripts?
有人可以帮我正确配置这些容器以执行 php 脚本吗?
P.S.I run containers via docker-composer like this:
PS我通过 docker-composer 运行容器,如下所示:
docker-compose up
docker-compose up
from the project root directory.
从项目根目录。
采纳答案by Vincent De Smet
Don't hardcode ip of containers in nginx config, docker link adds the hostname of the linked machine to the hosts file of the container and you should be able to ping by hostname.
不要在 nginx 配置中硬编码容器的 ip,docker link 将链接机器的主机名添加到容器的主机文件中,您应该能够通过主机名 ping。
EDIT: Docker 1.9 Networking no longer requires you to link containers, when multiple containers are connected to the same network, their hosts file will be updated so they can reach each other by hostname.
编辑:Docker 1.9 网络不再需要您链接容器,当多个容器连接到同一网络时,它们的主机文件将被更新,以便它们可以通过主机名相互访问。
Every time a docker container spins up from an image (even stop/start-ing an existing container) the containers get new ip's assigned by the docker host. These ip's are not in the same subnet as your actual machines.
每次 docker 容器从镜像中启动(甚至停止/启动现有容器)时,容器都会获得 docker 主机分配的新 IP。这些 ip 与您的实际机器不在同一个子网中。
see docker linking docs(this is what compose uses in the background)
请参阅 docker 链接文档(这是 compose 在后台使用的内容)
but more clearly explained in the docker-compose
docs on links & expose
但docker-compose
在链接和公开的文档中更清楚地解释了
links
links: - db - db:database - redis
An entry with the alias' name will be created in /etc/hosts inside containers for this service, e.g:
172.17.2.186 db 172.17.2.186 database 172.17.2.187 redis
expose
Expose ports without publishing them to the host machine- they'll only be accessible to linked services. Only the internal port can be specified.
链接
links: - db - db:database - redis
将在此服务的容器内的 /etc/hosts 中创建具有别名名称的条目,例如:
172.17.2.186 db 172.17.2.186 database 172.17.2.187 redis
暴露
公开端口而不将它们发布到主机——它们只能被链接的服务访问。只能指定内部端口。
and if you set up your project to get the ports + other credentials through environment variables, links automatically set a bunch of system variables:
如果您将项目设置为通过环境变量获取端口 + 其他凭据,则链接会自动设置一堆系统变量:
To see what environment variables are available to a service, run
docker-compose run SERVICE env
.
name_PORT
Full URL, e.g. DB_PORT=tcp://172.17.0.5:5432
name_PORT_num_protocol
Full URL, e.g.
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
name_PORT_num_protocol_ADDR
Container's IP address, e.g.
DB_PORT_5432_TCP_ADDR=172.17.0.5
name_PORT_num_protocol_PORT
Exposed port number, e.g.
DB_PORT_5432_TCP_PORT=5432
name_PORT_num_protocol_PROTO
Protocol (tcp or udp), e.g.
DB_PORT_5432_TCP_PROTO=tcp
name_NAME
Fully qualified container name, e.g.
DB_1_NAME=/myapp_web_1/myapp_db_1
要查看服务可以使用哪些环境变量,请运行
docker-compose run SERVICE env
.
name_PORT
完整 URL,例如 DB_PORT=tcp://172.17.0.5:5432
name_PORT_num_protocol
完整网址,例如
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
name_PORT_num_protocol_ADDR
容器的 IP 地址,例如
DB_PORT_5432_TCP_ADDR=172.17.0.5
name_PORT_num_protocol_PORT
暴露的端口号,例如
DB_PORT_5432_TCP_PORT=5432
name_PORT_num_protocol_PROTO
协议(tcp 或 udp),例如
DB_PORT_5432_TCP_PROTO=tcp
name_NAME
完全限定的容器名称,例如
DB_1_NAME=/myapp_web_1/myapp_db_1
回答by Rafael Quintela
I know it is kind an old post, but I've had the same problem and couldn't understand why your code didn't work. After a LOT of tests I've found out why.
我知道这是一篇旧帖子,但我遇到了同样的问题,无法理解为什么您的代码不起作用。经过大量测试,我找到了原因。
docker-compose.yml
docker-compose.yml
nginx:
build: .
ports:
- "80:80"
links:
- fpm
fpm:
image: php:fpm
ports:
- ":9000"
# seems like fpm receives the full path from nginx
# and tries to find the files in this dock, so it must
# be the same as nginx.root
volumes:
- ./:/complex/path/to/files/
/etc/nginx/conf.d/default.conf
/etc/nginx/conf.d/default.conf
server {
listen 80;
# this path MUST be exactly as docker-compose.fpm.volumes,
# even if it doesn't exist in this dock.
root /complex/path/to/files;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/.+\.php(/|$) {
fastcgi_pass fpm:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Dockerfile
文件
FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/
回答by iKanor
As pointed out before, the problem was that the files were not visible by the fpm container. However to share data among containers the recommended pattern is using data-only containers(as explained in this article).
如前所述,问题在于 fpm 容器看不到这些文件。然而,为了在容器之间共享数据,推荐的模式是使用纯数据容器(如本文所述)。
Long story short: create a container that just holds your data, share it with a volume, and link this volume in your apps with volumes_from
.
长话短说:创建一个容器来保存您的数据,与一个卷共享它,并在您的应用程序中使用volumes_from
.
Using compose (1.6.2 in my machine), the docker-compose.yml
file would read:
使用 compose(在我的机器中为 1.6.2),docker-compose.yml
文件将显示为:
version: "2"
services:
nginx:
build:
context: .
dockerfile: nginx/Dockerfile
ports:
- "80:80"
links:
- fpm
volumes_from:
- data
fpm:
image: php:fpm
volumes_from:
- data
data:
build:
context: .
dockerfile: data/Dockerfile
volumes:
- /var/www/html
Note that data
publishes a volume that is linked to the nginx
and fpm
services. Then the Dockerfile
for the dataservice, that contains your source code:
请注意,data
发布链接到nginx
和fpm
服务的卷。然后是包含您的源代码Dockerfile
的数据服务:
FROM busybox
# content
ADD path/to/source /var/www/html
And the Dockerfile
for nginx, that just replaces the default config:
而Dockerfile
对于 nginx,它只是替换了默认配置:
FROM nginx
# config
ADD config/default.conf /etc/nginx/conf.d
For the sake of completion, here's the config file required for the example to work:
为了完成起见,这里是示例工作所需的配置文件:
server {
listen 0.0.0.0:80;
root /var/www/html;
location / {
index index.php index.html;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
}
which just tells nginx to use the shared volume as document root, and sets the right config for nginx to be able to communicate with the fpm container (i.e.: the right HOST:PORT
, which is fpm:9000
thanks to the hostnames defined by compose, and the SCRIPT_FILENAME
).
它只是告诉 nginx 使用共享卷作为文档根目录,并为 nginx 设置正确的配置,以便能够与 fpm 容器进行通信(即:正确的HOST:PORT
,这要fpm:9000
归功于 compose 定义的主机名和SCRIPT_FILENAME
)。
回答by DavidT
New Answer
新答案
Docker Compose has been updated. They now have a version 2 file format.
Docker Compose 已更新。他们现在有一个版本 2 的文件格式。
Version 2 files are supported by Compose 1.6.0+ and require a Docker Engine of version 1.10.0+.
Compose 1.6.0+ 支持版本 2 文件,并且需要 1.10.0+ 版本的 Docker 引擎。
They now support the networking feature of Docker which when run sets up a default network called myapp_default
他们现在支持 Docker 的网络功能,运行时会设置一个名为myapp_default的默认网络
From their documentationyour file would look something like the below:
从他们的文档中,您的文件将如下所示:
version: '2'
services:
web:
build: .
ports:
- "8000:8000"
fpm:
image: phpfpm
nginx
image: nginx
As these containers are automatically added to the default myapp_defaultnetwork they would be able to talk to each other. You would then have in the Nginx config:
由于这些容器会自动添加到默认的myapp_default网络中,因此它们将能够相互通信。然后你会在 Nginx 配置中:
fastcgi_pass fpm:9000;
fastcgi_pass fpm:9000;
Also as mentioned by @treeface in the comments remember to ensure PHP-FPM is listening on port 9000, this can be done by editing /etc/php5/fpm/pool.d/www.conf
where you will need listen = 9000
.
同样正如@treeface 在评论中提到的,请记住确保 PHP-FPM 正在侦听端口 9000,这可以通过编辑/etc/php5/fpm/pool.d/www.conf
您需要的地方来完成listen = 9000
。
Old Answer
旧答案
I have kept the below here for those using older version of Docker/Docker compose and would like the information.
我为那些使用旧版本 Docker/Docker compose 的人保留了以下内容,并希望获得这些信息。
I kept stumbling upon this question on google when trying to find an answer to this question but it was not quite what I was looking for due to the Q/A emphasis on docker-compose (which at the time of writing only has experimental support for docker networking features). So here is my take on what I have learnt.
当我试图找到这个问题的答案时,我一直在 google 上偶然发现这个问题,但由于 Q/A 强调 docker-compose(在撰写本文时仅对docker 网络功能)。所以这是我对我所学到的东西的看法。
Docker has recently deprecated its linkfeature in favour of its networks feature
Therefore using the Docker Networks feature you can link containers by following these steps. For full explanations on options read up on the docs linked previously.
因此,使用 Docker 网络功能,您可以按照以下步骤链接容器。有关在先前链接的文档中阅读的选项的完整说明。
First create your network
首先创建您的网络
docker network create --driver bridge mynetwork
Next run your PHP-FPM container ensuring you open up port 9000 and assign to your new network (mynetwork
).
接下来运行您的 PHP-FPM 容器,确保您打开端口 9000 并分配给您的新网络 ( mynetwork
)。
docker run -d -p 9000 --net mynetwork --name php-fpm php:fpm
The important bit here is the --name php-fpm
at the end of the command which is the name, we will need this later.
这里重要的一点是--name php-fpm
命令末尾的名称,我们稍后会用到它。
Next run your Nginx container again assign to the network you created.
接下来再次运行您的 Nginx 容器,并将其分配给您创建的网络。
docker run --net mynetwork --name nginx -d -p 80:80 nginx:latest
For the PHP and Nginx containers you can also add in --volumes-from
commands etc as required.
对于 PHP 和 Nginx 容器,您还可以--volumes-from
根据需要添加命令等。
Now comes the Nginx configuration. Which should look something similar to this:
现在是 Nginx 配置。看起来应该与此类似:
server {
listen 80;
server_name localhost;
root /path/to/my/webroot;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
}
}
Notice the fastcgi_pass php-fpm:9000;
in the location block. Thats saying contact container php-fpm
on port 9000
. When you add containers to a Docker bridge network they all automatically get a hosts file update which puts in their container name against their IP address. So when Nginx sees that it will know to contact the PHP-FPM container you named php-fpm
earlier and assigned to your mynetwork
Docker network.
注意fastcgi_pass php-fpm:9000;
位置块中的 。这就是说php-fpm
在 port 上联系容器9000
。当您将容器添加到 Docker 桥接网络时,它们都会自动获取主机文件更新,该更新将容器名称与 IP 地址相对应。因此,当 Nginx 看到它时,它会知道联系您php-fpm
之前命名并分配给您的mynetwork
Docker 网络的 PHP-FPM 容器。
You can add that Nginx config either during the build process of your Docker container or afterwards its up to you.
您可以在 Docker 容器的构建过程中或之后添加该 Nginx 配置,这取决于您。
回答by Phillip
As previous answers have solved for, but should be stated very explicitly: the php code needs to live in the php-fpm container, while the static files need to live in the nginx container. For simplicity, most people have just attached all the code to both, as I have also done below. If the future, I will likely separate out these different parts of the code in my own projects as to minimize which containers have access to which parts.
正如之前的答案已经解决了,但应该非常明确地说明:php 代码需要存在于 php-fpm 容器中,而静态文件需要存在于 nginx 容器中。为简单起见,大多数人只是将所有代码附加到两者上,正如我在下面所做的那样。如果将来,我可能会在自己的项目中将代码的这些不同部分分开,以尽量减少哪些容器可以访问哪些部分。
Updated my example files below with this latest revelation (thank you @alkaline )
用这个最新的启示更新了我下面的示例文件(谢谢@alkaline)
This seems to be the minimum setup for docker 2.0 forward(because things got a lot easier in docker 2.0)
这似乎是 docker 2.0 forward 的最低设置(因为在 docker 2.0 中事情变得容易多了)
docker-compose.yml:
docker-compose.yml:
version: '2'
services:
php:
container_name: test-php
image: php:fpm
volumes:
- ./code:/var/www/html/site
nginx:
container_name: test-nginx
image: nginx:latest
volumes:
- ./code:/var/www/html/site
- ./site.conf:/etc/nginx/conf.d/site.conf:ro
ports:
- 80:80
(UPDATED the docker-compose.yml above: For sites that have css, javascript, static files, etc, you will need those files accessible to the nginx container. While still having all the php code accessible to the fpm container. Again, because my base code is a messy mix of css, js, and php, this example just attaches all the code to both containers)
(更新了上面的 docker-compose.yml:对于具有 css、javascript、静态文件等的站点,您将需要 nginx 容器可以访问这些文件。同时仍然让 fpm 容器可以访问所有 php 代码。同样,因为我的基本代码是 css、js 和 php 的混乱组合,这个例子只是将所有代码附加到两个容器中)
In the same folder:
在同一个文件夹中:
site.conf:
站点配置文件:
server
{
listen 80;
server_name site.local.[YOUR URL].com;
root /var/www/html/site;
index index.php;
location /
{
try_files $uri =404;
}
location ~ \.php$ {
fastcgi_pass test-php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
In folder code:
在文件夹代码中:
./code/index.php:
./code/index.php:
<?php
phpinfo();
and don't forget to update your hosts file:
并且不要忘记更新您的主机文件:
127.0.0.1 site.local.[YOUR URL].com
and run your docker-compose up
并运行你的 docker-compose up
$docker-compose up -d
and try the URL from your favorite browser
并尝试使用您喜欢的浏览器中的 URL
site.local.[YOUR URL].com/index.php
回答by leberknecht
I think we also need to give the fpm container the volume, dont we? So =>
我认为我们还需要为 fpm 容器提供音量,不是吗?所以=>
fpm:
image: php:fpm
volumes:
- ./:/var/www/test/
If i dont do this, i run into this exception when firing a request, as fpm cannot find requested file:
如果我不这样做,我会在触发请求时遇到此异常,因为 fpm 找不到请求的文件:
[error] 6#6: *4 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 172.17.42.1, server: localhost, request: "GET / HTTP/1.1", upstream: "fastcgi://172.17.0.81:9000", host: "localhost"
[错误] 6#6:*4 FastCGI 在 stderr 中发送:“主脚本未知”,同时从上游读取响应头,客户端:172.17.42.1,服务器:localhost,请求:“GET / HTTP/1.1”,上游:“fastcgi” ://172.17.0.81:9000”,主机:“本地主机”
回答by myol
For anyone else getting
对于其他任何人
Nginx 403 error: directory index of [folder] is forbidden
Nginx 403 错误:[文件夹] 的目录索引被禁止
when using index.php
while index.html
works perfectly and having included index.php
in the index in the server block of their site config in sites-enabled
当使用index.php
whileindex.html
工作完美并包含index.php
在其站点配置的服务器块中的索引中时sites-enabled
server {
listen 80;
# this path MUST be exactly as docker-compose php volumes
root /usr/share/nginx/html;
index index.php
...
}
Make sure your nginx.conf file at /etc/nginx/nginx.conf
actually loads your site config in the http
block...
确保您的 nginx.conf 文件/etc/nginx/nginx.conf
实际上在http
块中加载了您的站点配置...
http {
...
include /etc/nginx/conf.d/*.conf;
# Load our websites config
include /etc/nginx/sites-enabled/*;
}