如何正确链接 php-fpm 和 Nginx Docker 容器?

我试图连接两个不同的容器:

问题是 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"

Dockerfile,我用它来构建一个基于 nginx 的自定义图像:

FROM nginx


# Change Nginx config here...
RUN rm /etc/nginx/conf.d/default.conf
ADD ./default.conf /etc/nginx/conf.d/

最后,这是我自定义的 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;
}
}

有人能帮我正确配置这些容器来执行 php 脚本吗?

附言。 我通过码头作曲家这样运行集装箱:

docker-compose up

从项目根目录。

225120 次浏览

不要在 nginx 配置中硬编码容器的 ip,docker 链接将链接机器的主机名添加到容器的主机文件中,您应该能够通过主机名 ping。

编辑: Docker 1.9网络不再需要你链接容器,当多个容器连接到同一个网络时,它们的主机文件将被更新,这样它们就可以通过主机名到达彼此。

每当一个 docker 容器从一个映像旋转起来(甚至停止/启动一个现有容器) ,这个容器就会得到 docker 主机分配的新 ip。这些 IP 地址与您的实际计算机不在同一个子网中。

请参阅 docker link docs (这是 Comose 在后台使用的内容)

但更清楚地解释了在 docker-compose文档的链接和曝光

链接

links:
- db
- db:database
- redis

在这个服务的容器内的/etc/hosts 中将创建一个别名条目,例如:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

曝光

公开端口 而不把它们发布到主机上-它们将只是 链接服务的可访问性。只能指定内部端口。

如果您将项目设置为通过环境变量获得端口 + 其他凭据,链接自动设置一系列系统变量:

要查看服务可以使用哪些环境变量,请运行 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

我认为我们还需要给 fpm 容器体积,不是吗

fpm:
image: php:fpm
volumes:
- ./:/var/www/test/

如果我不这样做,当触发一个请求时,我会遇到这个异常,因为 fpm 无法找到请求的文件:

[错误]6 # 6: * 4 FastCGI 在从上游读取响应头时发送 stderr: “主脚本未知”,客户端: 172.17.42.1,服务器: localhost,请求: “ GET/HTTP/1.1”,上游: “ FastCGI://172.17.0.81:9000”,主机: “ localhost”

我知道这是一个老职位,但我有同样的问题,不能理解为什么你的代码不工作。 经过大量的测试,我终于找到了原因。

似乎 fpm 从 nginx 接收完整路径并试图在 fpm 容器中查找文件,因此它必须与 nginx 配置中的 server.root完全相同,即使它不存在于 nginx 容器中。

示范:

码头作曲

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

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;
}
}

文件夹

FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/

新答案

Docker Compose 已经更新。他们现在有一个 版本2的档案格式

Compose 1.6.0 + 支持 Version 2文件,并且需要版本1.10.0 + 的 Docker Engine。

它们现在支持 Docker 的网络特性,当运行时会设置一个名为 Myapp _ default的默认网络

他们的文件你的文件看起来如下:

version: '2'


services:
web:
build: .
ports:
- "8000:8000"
fpm:
image: phpfpm
nginx
image: nginx

当这些容器被自动添加到默认的 Myapp _ default网络时,它们将能够相互通信。然后在 Nginx 配置中就会有:

fastcgi_pass fpm:9000;

另外,正如@treeface 在评论中提到的,请记住要确保 PHP-FPM 正在监听端口9000,这可以通过编辑 /etc/php5/fpm/pool.d/www.conf来完成,在那里您将需要 listen = 9000

老答案

我已经为那些使用旧版本的 Docker/Docker 编写的用户保留了下面的内容,并希望获得相关信息。

当我试图找到这个问题的答案时,我不断在谷歌上偶然发现这个问题,但是这并不完全是我所寻找的,因为问答强调了 docker-compose (在写这篇文章的时候,它只有对 docker 网络功能的实验性支持)。因此,以下是我对我所学到的东西的看法。

Docker 公司最近推出了 不赞成它的联系功能,以支持其 网络功能

因此,使用 Docker Networks 特性,您可以通过以下步骤链接容器。有关选项的完整解释,请阅读以前链接的文档。

首先创建您的网络

docker network create --driver bridge mynetwork

接下来运行 PHP-FPM 容器,确保打开端口9000并分配给新的网络(mynetwork)。

docker run -d -p 9000 --net mynetwork --name php-fpm php:fpm

这里重要的一点是命令末尾的 --name php-fpm,也就是名称,我们稍后将需要它。

接下来再次运行 Nginx 容器,将其分配给您创建的网络。

docker run --net mynetwork --name nginx -d -p 80:80 nginx:latest

对于 PHP 和 Nginx 容器,您还可以根据需要添加 --volumes-from命令等。

现在是 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;
}
}

注意位置块中的 fastcgi_pass php-fpm:9000;。也就是说联系港口 9000上的集装箱 php-fpm。当您将容器添加到 Docker 桥网络时,它们都会自动获得一个主机文件更新,该更新会将容器名称与其 IP 地址进行对比。因此,当 Nginx 看到它将知道联系 PHP-FPM 容器您命名为 php-fpm之前,并分配给您的 mynetwork Docker 网络。

您可以在 Docker 容器的构建过程中添加 Nginx 配置,也可以在构建过程之后自行添加。

如前所述,问题在于 fpm 容器不能看到这些文件。然而,为了在容器之间共享数据,推荐的模式是使用 纯数据容器(如 这篇文章所解释的)。

长话短说: 创建一个容器,只是保存您的数据,共享它的卷,并链接这个卷在您的应用程序与 volumes_from

使用 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

请注意,data发布一个链接到 nginxfpm服务的卷。然后是用于 资料服务的 Dockerfile,它包含您的源代码:

FROM busybox


# content
ADD path/to/source /var/www/html

而 nginx 的 Dockerfile只是替换了默认配置:

FROM nginx


# config
ADD config/default.conf /etc/nginx/conf.d

为了便于完成,下面是示例工作所需的配置文件:

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;
}
}

它只是告诉 nginx 使用共享卷作为文档根,并为 nginx 设置正确的配置,以便能够与 fpm 容器通信(即: 正确的 HOST:PORT,它是 fpm:9000,这要感谢由 compose 定义的主机名和 SCRIPT_FILENAME)。

正如前面的答案所解决的,但是应该非常明确地说明: php 代码需要放在 php-fpm 容器中,而静态文件需要放在 nginx 容器中。为了简单起见,大多数人只是将所有代码附加到两者上,正如我在下面所做的那样。如果将来,我可能会在我自己的项目中将这些代码的不同部分分离出来,以尽量减少哪些容器可以访问哪些部分。

用这个最新的发现更新了我下面的示例文件(谢谢@堿性)

这似乎是 Docker 2.0 forward 的最低设置 (因为在 Docker 2.0中事情变得简单多了)

译文:

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

(更新了上面的 docker-compose. yml: 对于那些拥有 css、 javascript、静态文件等的站点,你需要这些文件能够被 nginx 容器访问。同时仍然可以访问 fpm 容器中的所有 php 代码。同样,因为我的基本代码是 css、 js 和 php 的混合体,所以这个示例只是将所有代码附加到两个容器中)

在同一个文件夹中:

官方网站:

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;
}
}

文件夹代码:

./code/index.php:

<?php
phpinfo();

别忘了更新你的主机文件:

127.0.0.1 site.local.[YOUR URL].com

运行你的码头-组成

$docker-compose up -d

并尝试从您最喜欢的浏览器的 URL

site.local.[YOUR URL].com/index.php

对于其他人来说

Nginx 403错误: 禁止[文件夹]的目录索引

当使用 index.php,而 index.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


...
}

确保 /etc/nginx/nginx.conf处的 nginx.conf 文件在 http块中实际加载站点配置..。

http {


...


include /etc/nginx/conf.d/*.conf;


# Load our websites config
include /etc/nginx/sites-enabled/*;
}