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


102

我正在尝试链接2个单独的容器:

问题是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脚本吗?

PS 我像这样通过docker-composer运行容器:

docker-compose up

从项目根目录。


1
到目前为止,您如何尝试配置它们,或者使用了什么代码。请不要让我猜我在猜我是垃圾。
马修·布朗又

1
@MatthewBrown Huh,我将代码放在GitHub上的公共存储库中,并认为这足够了,但是您是对的,最好在我的问题中在此处显示代码。
维克多·博沙斯基

当图像旋转时,您可以docker exec进入正在运行的容器并ping fpm吗?
Vincent De Smet 2015年

1
@MatthewBrown是的,我赢了,谢谢
Victor Bocharsky 2015年

1
PS I还实现了将 Vagrant和Ansible 链接起来NginxPHP-FPM一起使用的工作解决方案。如果需要,请查看我的回购github.com/bocharsky-bw/vagrant-ansible-docker
Victor Bocharsky 2015年

Answers:


32

不要在nginx config中对容器的ip进行硬编码,docker link将链接机器的主机名添加到容器的hosts文件中,您应该能够按主机名ping。

编辑:Docker 1.9 Networking不再需要您链接容器,当多个容器连接到同一网络时,它们的主机文件将被更新,以便它们可以通过主机名相互访问。

每次docker容器从映像启动(甚至停止/启动现有容器)时,这些容器都会获得docker主机分配的新IP。这些ip与您的实际计算机不在同一子网中。

查看docker链接文档(这是compose在后台使用的内容)

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

完整网址,例如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


2
您也不需要在主机上发布端口9000,除非在主机上直接对端口进行故障排除,否则链接的Docker容器之间的端口是打开的。
文森特·德·斯梅特

是的,您说得对,谢谢。就我而言,我应该使用fastcgi_pass fpm:9000而不是直接IP。我不知道Docker会自动将其添加到主机中,这很糟糕。
Victor Bocharsky

那么端口,那么最好使用暴露而不是端口?还是我不能使用任何一个端口并公开指令,因为链接的容器可以访问此端口?
Victor Bocharsky

抱歉,您无法提供回复-我想您可能需要使用暴露,抱歉,我现在无法检查
Vincent De Smet 2015年

2
--links根据您引用的Docker文档,现在已过时。目前仍支持它们,但明显的计划是将它们淘汰。
therobyouknow

85

我知道这是一篇很老的文章,但是我遇到了同样的问题,无法理解为什么您的代码无法正常工作。经过大量测试后,我发现了原因。

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

展示:

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

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

Docker文件

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

4
做得好!!!这就是重点!我将nginx根设置为除/var/www/html失败以外的其他路径。
Alfred Huang

3
另外,仅需注意的:9000是容器中正在使用的端口,而不是暴露给主机的端口。花了我2个小时来解决这个问题。希望您不必这样做。
shriek

1
services.fpm.ports is invalid: Invalid port ":9000", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
030

4
实际上,您根本不需要ports在此处包含任何部分。expose如果图像中还没有它(可能是),则可能只需要它。如果要进行容器间通信,则不应公开PHP-FPM端口。
Seer

一直在寻找解决方案,AH01071: Got error 'Primary script unknown\n'而php-fpm容器必须与Web节点共享同一目录才是解决方案!
cptPH

23

如前所述,问题是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

Dockerfile对于nginx,它只是替换默认配置:

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容器通信(即:right HOST:PORT,这要fpm:9000感谢compose定义的主机名和SCRIPT_FILENAME)。


看起来数据没有从主机更新到容器,并且当我执行docker ps -a时,我看到数据容器停止了,这是问题吗?
Aftab Naveed

2
那是预期的行为。仅数据容器不会运行任何命令,只会被列为已停止。同样,Dockerfile数据容器的会在构建时将源复制到容器中。因此,如果您更改主机中的文件,它们将不会更新。如果要在主机和容器之间共享源,则需要挂载目录。data在撰写文件中更改服务以加载image: busybox,然后在volumes部分中输入./sources:/var/www/html,其中./sources是主机中源的路径。
iKanor

16

新答案

Docker Compose已更新。现在,它们具有版本2文件格式

Compose 1.6.0+支持版本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的用户,我将在此处保存以下内容,并希望获得相关信息。

在尝试找到该问题的答案时,我一直在google上徘徊,但由于Q / A对docker-compose的重视(我在撰写本文时仅对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;位置块中的。就是说联系php-fpm港口的集装箱9000。当您将容器添加到Docker桥接网络时,它们都会自动获取主机文件更新,该更新会将其容器名称与IP地址相对应。因此,当Nginx看到它将知道与您php-fpm先前命名并分配给您的PHP-FPM容器联系时mynetwork Docker网络。

您可以在Docker容器的构建过程中或之后由您自己添加Nginx配置。


还要记住确保php-fpm正在侦听端口9000。该端口listen = 9000位于中/etc/php5/fpm/pool.d/www.conf
treeface '16

感谢@treeface好点。我已更新您的评论。
DavidT

8

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

使用最新的启示更新了以下示例文件(谢谢@alkaline)

这似乎是docker 2.0 forward的最低设置 (因为在docker 2.0中事情变得容易得多)

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

更新了上面的docker-compose.yml:对于具有css,javascript,静态文件等的网站,您将需要nginx容器可访问这些文件。同时仍可让fpm容器访问所有php代码。同样,因为我的基本代码是css,js和php的混乱混合,此示例仅将所有代码附加到两个容器中)

在同一文件夹中:

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

在文件夹代码中:

./code/index.php:

<?php
phpinfo();

并且不要忘记更新主机文件:

127.0.0.1 site.local.[YOUR URL].com

并运行您的docker-compose

$docker-compose up -d

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

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

1
您的nginx配置文件假定您的网站只有php文件。最好的做法是为静态文件(jpg,txt,svg,...)创建nginx位置规则,并避免使用php解释器。在这种情况下,nginx和php容器都需要访问网站文件。@iKanor上面的答案可以解决这个问题。
伯纳德

感谢@Alkaline,静态文件是我的原始答案有问题。实际上,nginx至少确实需要该机器本地的css和js文件才能正常工作。
菲利普(Phillip)

7

我认为我们还需要给fpm容器增加体积,不是吗?所以=>

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

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

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


1
是的,你是对的!我们必须与fpm和nginx共享文件
Victor Bocharsky

我在GitHub上NginxPHP-FPM上都有工作示例
Victor Bocharsky 2015年

1

对于其他任何人

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

当使用index.phpwhile时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

    ...
}

确保位于的nginx.conf文件/etc/nginx/nginx.conf实际上将您的站点配置加载到http块中...

http {

    ...

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

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

感谢这个,古老但仍然有用的东西,我不得不使用/ usr / share / nginx / html👍,谢谢
Simon Davies
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.