J’ai récemment revu l’organisation des containers Docker présents sur mon serveur et j’ai essayé d’utiliser le plus possible les images “officielles” des technos dont j’avais besoin. Ici, nous allons mettre en place un Nginx pour servir des pages statique (HTML et autres ressources) mais également en mesure de gérer du contenu PHP.

Objectif de l’infra

Le but est d’avoir un container avec Nginx pour servir du contenu statique et dynamique (PHP). Il faudra configurer Nginx pour rediriger les requêtes de ressources PHP vers un second container qui embarquera PHP-FPM (FastCGI Process Manager).

Nous aurons donc besoin de deux images Docker :

Par préférence personnelle, nous allons utiliser docker-compose pour configurer les containers (Installer Docker Compose).

Le container Nginx

Tout d’abord, il nous faut créer l’arborescence de répertoire dont nous allons avoir besoin, ainsi que les fichiers de journalisation avec les privilèges adéquats :

Console
host:~# mkdir -p docker-web/www                  # Webroot dans lequel sera stocké le contenu statique du site
host:~# mkdir -p docker-web/log                  # Pour enregistrer les journaux de Nginx
host:~# touch docker-web/log/{error,access}.log  # Journaux pour Nginx
host:~# chmod a+rw docker-web/log/*              # Accessible en lecture/écriture pour tous (ce n'est pas l'idéal, si quelqu'un a une autre idée je suis preneur)

Nous aurons également besoin du fichier de configuration de Nginx. Il remplacera celui par défaut présent dans le container Nginx et permettra de facilement modifier la configuration du serveur sans avoir en entrer dans le container.

docker-web/nginx.conf
user                       nginx;
worker_processes           1;

error_log                  /var/log/nginx/error.log warn;
pid                        /var/run/nginx.pid;

events {
    worker_connections     1024;
}

http {
    include                /etc/nginx/mime.types;
    default_type           application/octet-stream;
    
    log_format             main  '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
    access_log             /var/log/nginx/access.log main;
    
    sendfile               on;
    keepalive_timeout      65;
    server_tokens          off;

    server {
        listen             80;
        server_name        localhost;
        
        location / {
            root           /usr/share/nginx/html;
            index          index.html index.htm;
        }
        
        error_page         500 502 503 504 /50x.html;
        location = /50x.html {
            root           /usr/share/nginx/html;
        }
    }
}

Pour gérer nos containers, nous allons utiliser docker-compose plutôt que de multiples docker run .... Docker Compose utilise un fichier de configuration YAML docker-compose.yml dans lequel sont définis nos containers et leurs options de démarrage.

On peut à présent configurer et démarrer le container Nginx :

docker-compose.yml
version: '3'

services:
    web-nginx:
        image: nginx:stable-alpine
        container_name: web-nginx
        volumes:
            - "./docker-web/www:/usr/share/nginx/html:ro"
            - "./docker-web/log:/var/log/nginx"
            - "./docker-web/nginx.conf:/etc/nginx/nginx.conf:ro"
        ports:
            - "127.0.0.1:80:80"
Console
host:~# docker-compose up -d

Le site est maintenant accessible sur le port TCP/80 de l’hôte, en local. Cependant, si vous vous rendez à l’adresse http://localhost/, vous obtiendrez une erreur 403 Forbidden car notre répertoire www est vide. Pour simplement vérifier que tout fonctionne, il suffit de créer un fichier index.html :

Console
host:~# echo 'hello world!' > docker-web/www/index.html
index.php

Le container PHP

Ne perdons pas de vu l’objectif : disposer d’un environnement Web capable d’interpréter PHP pour servir du contenu dynamique. Pour cela, nous allons mettre en place un second container qui embarquera PHP.

Tout d’abord, il faut modifier le fichier de configuration de Nginx pour lui préciser de rediriger les requêtes de ressources PHP vers le container que nous venons de mettre en place. Nous ajoutons index.php dans la directive index du serveur, et les instructions fastcgi pour les fichiers PHP (i.e. les fichiers dont l’extension est .php : location ~ \.php$).

docker-web/nginx.conf
user                       nginx;
worker_processes           1;

error_log                  /var/log/nginx/error.log warn;
pid                        /var/run/nginx.pid;

events {
    worker_connections     1024;
}

http {
    include                /etc/nginx/mime.types;
    default_type           application/octet-stream;
    
    log_format             main  '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
    access_log             /var/log/nginx/access.log main;
    
    sendfile               on;
    keepalive_timeout      65;
    server_tokens          off;

    server {
        listen             80;
        server_name        localhost;
        
        location / {
            root           /usr/share/nginx/html;
            index          index.php index.html index.htm;
        }
        
        error_page         500 502 503 504 /50x.html;
        location = /50x.html {
            root           /usr/share/nginx/html;
        }

        location ~ \.php$ {
            root           /usr/share/nginx/html;
            include        fastcgi_params;
            fastcgi_pass   web-php:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /script$fastcgi_script_name;
        }
    }
}

Nous aurons besoin également d’un fichier index.php afin de pouvoir tester que tout fonctionne une fois que le container sera en place.

Console
host:~# echo '<?php phpinfo();' > docker-web/www/index.php

On peut à présent configurer et démarrer le container PHP :

docker-compose.yml
version: '3'

services:
    web-nginx:
        image: nginx:stable-alpine
        container_name: web-nginx
        volumes:
            - "./docker-web/www:/usr/share/nginx/html:ro"
            - "./docker-web/log:/var/log/nginx"
            - "./docker-web/nginx.conf:/etc/nginx/nginx.conf:ro"
        ports:
            - "127.0.0.1:80:80"

    web-php:
        image: php:fpm-alpine
        container_name: web-php
        volumes:
            - "./docker-web/www:/script:ro"
Console
host:~# docker-compose up -d
index.php

Références

  1. PHP (Docker Official Images) - Docker Hub
  2. Nginx (Docker Official Images) - Docker Hub