How to correctly link php-fpm and Nginx Docker containers?

后端 未结 7 964
天涯浪人
天涯浪人 2020-12-02 04:20

I am trying to link 2 separate containers:

  • nginx:latest
  • php:fpm

The problem is that php scripts do not work. Perhaps the php-fpm config

相关标签:
7条回答
  • 2020-12-02 04:29

    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.

    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.

    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.

    see docker linking docs (this is what compose uses in the background)

    but more clearly explained in the docker-compose docs on links & expose

    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.

    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

    0 讨论(0)
  • 2020-12-02 04:31

    For anyone else getting

    Nginx 403 error: directory index of [folder] is forbidden

    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

    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...

    http {
    
        ...
    
        include /etc/nginx/conf.d/*.conf;
    
        # Load our websites config 
        include /etc/nginx/sites-enabled/*;
    }
    
    0 讨论(0)
  • 2020-12-02 04:35

    New Answer

    Docker Compose has been updated. They now have a version 2 file format.

    Version 2 files are supported by Compose 1.6.0+ and require a Docker Engine of version 1.10.0+.

    They now support the networking feature of Docker which when run sets up a default network called myapp_default

    From their documentation your 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_default network they would be able to talk to each other. You would then have in the Nginx config:

    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.

    Old Answer

    I have kept the below here for those using older version of Docker/Docker compose and would like the information.

    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.

    Docker has recently deprecated its link feature 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.

    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).

    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.

    Next run your Nginx container again assign to the network you created.

    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.

    Now comes the Nginx configuration. Which should look something similar to this:

    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.

    You can add that Nginx config either during the build process of your Docker container or afterwards its up to you.

    0 讨论(0)
  • 2020-12-02 04:40

    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).

    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.

    Using compose (1.6.2 in my machine), the docker-compose.yml file would read:

    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 data service, that contains your source code:

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

    And the Dockerfile for nginx, that just replaces the default config:

    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).

    0 讨论(0)
  • 2020-12-02 04:42

    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.

    It seems like fpm receives the full path from nginx and tries to find the files in the fpm container, so it must be the exactly the same as server.root in the nginx config, even if it doesn't exist in the nginx container.

    To demonstrate:

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

    Dockerfile

    FROM nginx:latest
    COPY ./default.conf /etc/nginx/conf.d/
    
    0 讨论(0)
  • 2020-12-02 04:44

    I think we also need to give the fpm container the volume, dont we? So =>

    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:

    [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"

    0 讨论(0)
提交回复
热议问题