Apache et PHP-FPM dans des conteneurs séparés

Objectif

Créer 2 conteneurs séparés pour Apache 2.6 (Httpd) et PHP-FPM 8.1 sous Alpine 3.16.

Tutoriel

Arborescence

Commençons par créer un dossier dans lequel nous allons travailler :

mkdir httpd-phpfpm && cd httpd-phpfpm

Dans ce dossier, nous allons créer les dossiers pour les volumes persistants de notre conteneur Docker :

mkdir -p data conf

Fichier de configuration du VirtualHost

Dans le dossier conf, nous allons créer le fichier httpd.conf qui contiendra toute la configuration de Apache ainsi que notre virtual host :

ServerRoot "/usr/local/apache2"

Listen 8000

LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule deflate_module modules/mod_deflate.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule vhost_alias_module modules/mod_vhost_alias.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so

<IfModule unixd_module>
    User app
    Group app
</IfModule>

ServerName localhost
ServerAdmin <votre-adresse-email>

<Directory />
    AllowOverride none
    Require all denied
</Directory>

DocumentRoot "/var/www/html/"
<Directory "/var/www/html/">
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://phpfpm:9000"
</FilesMatch>

<IfModule dir_module>
    DirectoryIndex index.php
</IfModule>

<Files ".ht*">
    Require all denied
</Files>

ErrorLog /proc/self/fd/2

LogLevel warn

<IfModule log_config_module>
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
        LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    CustomLog /proc/self/fd/1 common
</IfModule>

<IfModule headers_module>
    RequestHeader unset Proxy early
</IfModule>

<IfModule mime_module>
    TypesConfig conf/mime.types

    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
</IfModule>

<IfModule proxy_html_module>
    Include conf/extra/proxy-html.conf
</IfModule>

Avant d'enregistrer et de fermer le fichier, n'oubliez pas de modifier les 2 valeurs des directives ServerName et ServerAdmin.

C'est le bloc ci-dessous qui va permettre à Apache d'interpreter le code PHP d'une page.

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://phpfpm:9000"
</FilesMatch>

Et le bloc ci-dessous précisera à Apache de rediriger les adresses terminant par / vers les fichiers index.php :

<IfModule dir_module>
    DirectoryIndex index.php
</IfModule>

Fichier PHP

Dans le fichier data, nous allons créer le fichier index.php qui contiendra simplement :

<?php phpinfo();

Ce fichier nous permettra de tester le bon fonctionnement entre les 2 conteneurs.

Fichier : httpd.Dockerfile

Pour déployer Httpd, on utilisera l'image httpd:alpine3.16, voici le fichier Dockerfile que nous allons utiliser :

FROM httpd:alpine3.16

COPY ./conf/httpd.conf /usr/local/apache2/conf/httpd.conf

RUN addgroup -g 1000 app \
&& adduser -D -H -h /var/www -s /sbin/nologin -G app -u 1000 app

RUN mkdir -p /var/www/html \
&& chown -R app:app /var/www /usr/local/apache2/logs

USER app:app

WORKDIR /var/www/html

EXPOSE 8000

CMD /usr/local/apache2/bin/httpd -D FOREGROUND

Voici quelques explications des directives du fichier :

  • On copie le fichier de configuration que nous avons créé précédemment.
  • On ajoute un nouvel utilisateur nommé app
  • On crée des dossiers et on modifie les droits sur les différents répertoires
  • On change l'utilisateur root par app
  • On expose le port 8000
  • On exécute httpd

Fichier : phpfpm.Dockerfile

Pour déployer PHP-FPM, on utilisera l'image php:8.1-fpm-alpine3.16, voici le fichier Dockerfile que nous allons utiliser :

FROM php:8.1-fpm-alpine3.16

COPY ./conf/php-fpm.conf /usr/local/etc/php-fpm.conf

RUN addgroup -g 1000 app \
&& adduser -D -H -h /var/www -s /sbin/nologin -G app -u 1000 app

RUN mkdir -p /var/www/html /var/log/php \
&& chown -R app:app /var/www /usr/local/etc/php/conf.d /var/log/php

USER app:app

WORKDIR /var/www/html

EXPOSE 9000

CMD php-fpm

Voici quelques explications des directives du fichier :

  • On copie le fichier de configuration que nous avons créé précédemment.
  • On ajoute un nouvel utilisateur nommé app
  • On crée des dossiers et on modifie les droits sur les différents répertoires
  • On change l'utilisateur root par app
  • On expose le port 9000
  • On exécute php-fpm

Fichier : docker-compose.yml

A la racine de notre projet (dossier httpd-phpfpm), nous allons créer un fichier docker-compose.yml contenant :

version: '3'
services:
  httpd:
    build:
      context: .
      dockerfile: httpd.Dockerfile
    ports:
      - 8000:8000
    volumes:
      - ./data:/var/www/html
    networks:
      - httpdphpfpm

  phpfpm:
    build:
      context: .
      dockerfile: phpfpm.Dockerfile
    expose:
      - 9000
    volumes:
      - ./data:/var/www/html
    networks:
      - httpdphpfpm

networks:
  httpdphpfpm:
    driver: bridge

Build et lancement

Pour terminer cette partie, lancer la commande ci-dessous pour construire et lancer les conteneurs :

docker-compose build && docker-compose up -d

Résultat

Vous pouvez visualiser votre page en ouvrant votre navigateur à l'adresse : http://localhost:8000