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

Vic*_*sky 86 php nginx docker dockerfile docker-compose

我想链接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"
Run Code Online (Sandbox Code Playgroud)

Dockerfile我使用了基于nginx的一个建立一个自定义图像:

FROM nginx

# Change Nginx config here...
RUN rm /etc/nginx/conf.d/default.conf
ADD ./default.conf /etc/nginx/conf.d/
Run Code Online (Sandbox Code Playgroud)

最后,这是我的自定义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;
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我正确配置这些容器来执行PHP脚本吗?

PS 我通过docker-composer运行容器,如下所示:

docker-compose up

从项目根目录.

小智 75

我知道这是一个老帖子,但我遇到了同样的问题,无法理解为什么你的代码不起作用.经过大量的测试,我发现了原因.

泊坞窗,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/
Run Code Online (Sandbox Code Playgroud)

/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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Dockerfile

FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/
Run Code Online (Sandbox Code Playgroud)

  • **做得好!**这就是重点!我将nginx root设置为除了`/ var/www/html`之外的替代路径,但是失败了. (3认同)
  • 另外,只需注意`:9000`是容器中使用的端口,而不是暴露给主机的端口.我花了2个小时来搞清楚这一点.希望你不必. (3认同)
  • `services.fpm.ports 无效:端口“:9000”无效,应为 [[remote_ip:]remote_port[-remote_port]:]port[/protocol]` (2认同)
  • 你根本不需要在这里包含`ports`部分.如果它不在图像中(它可能是),你可能只需要"暴露"它.如果您正在进行容器间通信,那么_不应该暴露PHP-FPM端口. (2认同)
  • 正在寻找“AH01071:出现错误‘主脚本未知\n’”的解决方案,并且 php-fpm 容器必须与 Web 节点共享同一目录就是解决方案! (2认同)

Vin*_*met 30

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

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

每当一个docker容器从图像中旋转时(甚至停止/启动现有容器),容器就会获得由docker主机分配的新ip.这些ip与实际机器不在同一子网中.

看到docker链接文档(这是后台使用的组合)

但在docker-compose关于链接和揭露的文档中更清楚地解释了

链接

links:
 - db
 - db:database
 - redis
Run Code Online (Sandbox Code Playgroud)

将在此服务的容器内的/ etc/hosts中创建具有别名'name的条目,例如:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis
Run Code Online (Sandbox Code Playgroud)

暴露

暴露端口而不将它们发布到主机 - 它们只能被链接服务访问.只能指定内部端口.

如果您设置项目以通过环境变量获取端口+其他凭据,链接会自动设置一堆系统变量:

要查看服务可用的环境变量,请运行docker-compose run SERVICE env.

name_PORT

完整URL,例如DB_PORT = tcp://172.17.0.5:5432

name_PORT_num_protocol

完整的URL,例如 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

  • 根据您参考的 docker 文档,`--links` 现在已过时。它们仍_当前_受支持,但明显的计划是将它们过时。 (3认同)
  • 您也不需要在主机上发布端口 9000,链接的 docker 容器之间的端口是开放的,除非您想直接从主机对端口进行故障排除。 (2认同)

iKa*_*nor 22

如前所述,问题是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
Run Code Online (Sandbox Code Playgroud)

请注意,data发布链接到nginxfpm服务的卷.然后是包含源代码Dockerfile数据服务:

FROM busybox

# content
ADD path/to/source /var/www/html
Run Code Online (Sandbox Code Playgroud)

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

FROM nginx

# config
ADD config/default.conf /etc/nginx/conf.d
Run Code Online (Sandbox Code Playgroud)

为了完成,这里是示例工作所需的配置文件:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

它只是告诉nginx使用共享卷作为文档根目录,并为nginx设置正确的配置,以便能够与fpm容器通信(即:右侧HOST:PORT,这要fpm:9000归功于由compose定义的主机名,以及SCRIPT_FILENAME).

  • 这是预期的行为.仅数据容器不运行任何命令,它将仅列为已停止.此外,数据容器的`Dockerfile`正在构建时将源复制到容器.这就是为什么如果更改主机中的文件,它们将不会更新.如果要共享主机和容器之间的源,则需要安装目录.更改compose文件中的`data`服务以加载`image:busybox`,并在`volumes`部分输入`./sources:/ var/www/html`,其中`./ sources`是你的路径主持人的来源. (2认同)

Dav*_*idT 14

新答案

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
Run Code Online (Sandbox Code Playgroud)

由于这些容器会自动添加到默认的myapp_default网络,因此它们可以相互通信.然后你会在Nginx配置中:

fastcgi_pass fpm:9000;

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

老答案

对于那些使用旧版Docker/Docker的人来说,我已经保留了下面这些信息.

当我试图找到这个问题的答案时,我一直在谷歌这个问题上磕磕绊绊,但由于Q/A强调docker-compose(在编写本文时只有实验支持),这并不是我想要的.码头网络功能).所以这是我对所学知识的看法.

Docker最近弃用了其链接功能,转而支持其网络功能

因此,使用Docker Networks功能可以按照以下步骤链接容器.有关选项的完整说明,请阅读之前链接的文档.

首先创建您的网络

docker network create --driver bridge mynetwork
Run Code Online (Sandbox Code Playgroud)

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

docker run -d -p 9000 --net mynetwork --name php-fpm php:fpm
Run Code Online (Sandbox Code Playgroud)

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

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

docker run --net mynetwork --name nginx -d -p 80:80 nginx:latest
Run Code Online (Sandbox Code Playgroud)

对于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;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意fastcgi_pass php-fpm:9000;位置块中的内容.多数民众赞成php-fpm在港口联系集装箱9000.将容器添加到Docker桥接网络时,它们都会自动获得主机文件更新,并根据其IP地址放入容器名称.因此,当Nginx发现它会知道要联系您php-fpm之前命名并分配给mynetworkDocker网络的PHP-FPM容器时.

您可以在Docker容器的构建过程中或之后添加该Nginx配置.


Phi*_*lip 8

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

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

这似乎是docker 2.0前进的最小设置 (因为在docker 2.0中事情变得容易多了)

泊坞窗,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
Run Code Online (Sandbox Code Playgroud)

(更新了上面的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在文件夹代码中:

./code/index.php:

<?php
phpinfo();
Run Code Online (Sandbox Code Playgroud)

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

127.0.0.1 site.local.[YOUR URL].com
Run Code Online (Sandbox Code Playgroud)

然后运行你的码头工作

$docker-compose up -d
Run Code Online (Sandbox Code Playgroud)

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

site.local.[YOUR URL].com/index.php
Run Code Online (Sandbox Code Playgroud)


leb*_*cht 6

我想我们还需要给fpm容器提供音量,不是吗?所以=>

fpm:
    image: php:fpm
    volumes:
        - ./:/var/www/test/
Run Code Online (Sandbox Code Playgroud)

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

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