Docker et Portainer part 5 – Customiser un conteneur PHP-FPM

Docker et Portainer

Salut à tous, dans le dernier TP docker je me suis attardé sur le partie réseau des conteneurs et stacks dans docker. Aujourd’hui on va regarder comment customiser un conteneur PHP-FPM. En effet, nous en sommes au 5ème TP Docker et Portainer mais on a toujours pas vu dans le détails comment ça se présente un conteneur, ni comment le personnaliser depuis une image existante.

Rappel des articles de la série « Docker et Portainer » :

Pourquoi PHP-FPM déjà?

En théorie un site WordPress, c’est pas bien compliqué, il vous faut à minima :

  • Un serveur web avec PHP genre (Apache ou Nginx et PHP) ;
  • Une base de données (genre MySql ou PostGre)

En général, PHP est installé comme un module de votre serveur web et c’est donc le moteur web qui s’occupe d’interpréter le PHP. Il y a une autre façon de mettre en œuvre PHP : en mode « FPM » (pour FastCGI Process Manager).

Pour l’utilisateur du site, il n’y a aucune différence. Pour l’administrateur, c’est complétement différent. Déjà vous vous retrouvez avec un service supplémentaire à faire tourner, mais il y a de nombreux avantages à utiliser FPM :

  • Plus rapide ;
  • Meilleurs maitrise des performances et de la consommation de ressources (celui-ci s’exécutant comme un service indépendant, il n’est pas tributaire du fonctionnement du serveur web)
  • Possibilité de séparation physique sur une machine dédié (ou un autre conteneur dans notre cas) (potentiellement partagé entre différents sites).
  • Gain de sécurité : le service s’exécutant avec ses propres permissions, vous pouvez mieux segmenter les droits si nécessaire et en cas de compromission vous avez mieux découpé votre infra et compliqué la vie de l’attaquant.

En contrepartie, c’est plus complexe à maintenir et mettre en place, vous allez rencontrer des problèmes de permissions ou de configuration et d’autres trucs spécifiques à FPM.

Customiser un conteneur PHP-FPM Docker

Vous trouverez les images officielles de PHP-FPM sur le docker hub de PHP sous les tags FPM*. Pour ce TP, je vais partir de cette version de l’image : 7.4-FPM. La documentation pour construire un Dockerfile est ici : mais en gros il faut comprendre qu’une image Docker, c’est simplement une succession d’instructions que docker est capable d’interpréter. Une ligne se présente presque toujours ainsi :

<CMD_DOCKER> [Parametres]

Avec CMD parmi les instructions existantes : ADD, RUN, FROM, ENV, etc. qui permettent toutes d’agir sur votre image. Vous pouvez donc démarrer d’une image de base (genre scratch) ou repartir et modifier une image existante avec le mot clé FROM.

On est dans ce second mode ici, en effet l’image PHP-FPM standard n’est pas personnalisée pour un site en production, il manque notamment des extensions pour PHP et des réglages spécifiques pour le fichier php.ini, ou la spécification d’un id/gid particulier pour l’utilisateur qui fera tourner le service. Donc notre image docker va hériter de notre base, soit :

FROM php:7.4-fpm

Changer l’id/gid de l’utilisateur

Dans mon cas, j’avais quelques soucis d’accès entre le serveur Nginx et PHP, un bon moyen de régler ça a simplement été de modifier l’id/gid de PHP pour les aligner sur celui du serveur web et de placer ensuite les permissions qui vont bien sur les dossiers du site. On modifie donc notre image ainsi :

# php-fpm-geekeries_org:latest
FROM php:7.4-fpm
RUN usermod -u 101 www-data

Ajouter des extensions à docker PHP-FPM

Rajouter des extensions dans une image déjà construite (voir avec du code déjà compilé), ça peut être un peu coton. La bonne nouvelle, c’est que l’équipe de PHP a prévu le coup et, a documenté comment faire ici pour les extensions les plus courantes en PHP. Du coup notre image devient :

# php-fpm-geekeries_org:latest
FROM php:7.4-fpm
ADD https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions /usr/local/bin/
RUN chmod uga+x /usr/local/bin/install-php-extensions && sync && \
    install-php-extensions pdo_mysql mysqli exif opcache imagick zip gd sockets
RUN pecl install redis-5.2.1 \
    && docker-php-ext-enable redis

Modifier php.ini pour la production

Dernier point, le fichier de configuration par défaut livré avec l’image docker PHP-FPM n’est pas vraiment « production ready »… du coup il faut le remplacer par celui prévu pour le run et dans mon cas il y avait encore quelques ajustements à faire que j’ai fait à l’aide de sed. Et donc notre image devient :

# php-fpm-geekeries_org:latest
FROM php:7.4-fpm
RUN usermod -u 101 www-data
ADD https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions /usr/local/bin/
RUN chmod uga+x /usr/local/bin/install-php-extensions && sync && \
    install-php-extensions pdo_mysql mysqli exif opcache imagick zip gd sockets
RUN pecl install redis-5.2.1 \
    && docker-php-ext-enable redis
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN sed -i "s/memory_limit = 128M/memory_limit = 512M/g" /usr/local/etc/php/php.ini
RUN sed -i "s/max_input_time = 60/max_input_time = 300/g" /usr/local/etc/php/php.ini
RUN sed -i "s/max_execution_time = 30/max_execution_time = 300/g" /usr/local/etc/php/php.ini
RUN sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 20M/g" /usr/local/etc/php/php.ini
RUN sed -i "s/;max_input_vars = 1000/;max_input_vars = 10000/g" /usr/local/etc/php/php.ini
RUN sed -i "s/post_max_size = 8M/post_max_size = 20M/g" /usr/local/etc/php/php.ini

Démarrer une image docker personnalisée

En ligne de commande

Alors en ligne de commande c’est un peu chiant, vous devrez créer un dossier vous déplacer dedans, y créer un fichier nommé Dockerfile et y mettre le contenu ci-dessus avant de construire l’image.

mkdir MyDockers/php-fpm-custom
cd MyDockers/php-fpm-custom
vim Dockerfile
# Ctrl-V de votre Dockerfile.
docker build -t php-fpm-custom .
Sending build context to Docker daemon 2.048kB
[...]
Successfully tagged php-fpm-custom:latest

Dans Portainer

Du coup, on peut aussi utiliser Portainer en allant dans Images -> Build a new image et copier le texte dans notre image directement puis laisser Portainer se débrouiller.

customiser un conteneur PHP-FPM

Si vous utilisez Portainer, je vous conseille quand même de conserver une copie de votre source quelque part, celui-ci ne fournissant pas un accès agréable à votre DockerFile d’origine une fois l’image construite. Mais à partir de là vous pourrez utiliser l’image en question dans vos stack comme n’importe quelle image du hub docker.

Sa propre docker registry

Une registry c’est comme un repo ou un git pour docker et docker fournit l’image qui va bien pour ça. Pour déployer une registry en local sur le serveur vous pouvez utiliser la stack suivante, par exemple (attention je ne configure pas d’authentification ni de chiffrement ici comme je n’expose pas de port à l’extérieur vu que l’accès ne sera pas partagé) :

version: "2"
services:
  registry:
    container_name: registry
    hostname: registry
    restart: unless-stopped
    image: registry:2
    #ports:
    #  - 5000:5000
    expose:
      - 5000
    volumes:
      - registry_data:/var/lib/registry 
    networks:
      backend_network:
        ipv4_address: 172.20.0.5
networks:
  Proxy_net:
    external:
      name: backend_network

Vous pouvez ensuite ajouter votre base d’image dans Portainer en allant dans Registries et ajouter l’url/ip/port de votre stack, comme ci dessous :

customiser un conteneur PHP-FPM

Du coup là, vous pouvez pousser votre image dans la registry ainsi, en commençant par vérifier qu’elle est présente localement en ligne de commande :

root@thrain4:~# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
php-fpm-custom latest d17ce4024f6b 3 weeks ago 648MB

Puis taguer là pour votre registry docker avant de la pousser dessus :

docker image tag php-fpm-custom 172.20.0.5:5000/php-fpm-custom
docker push 172.20.0.5:5000/php-fpm-custom

Note : si vous n’avez pas configuré https pour le registry ou non il se peut que vous deviez ajouter la ligne "insecure-registries": ["172.20.0.5:5000"] dans le fichier /etc/docker/daemon.json et redémarrer docker avant de pouvoir pousser l’image.

Vous pourrez ensuite appeler votre image dans vos stacks et autres docker compose avec le tag « 172.20.0.5:5000/php-fpm-custom:latestphp« . Et vous pouvez lister ce qui est présent dans votre registry en tapant sur l’API :

curl -X GET http://172.20.0.5:5000/v2/_catalog
{"repositories":["php-fpm-custom"]}

A partir de là vous (ou vos amis et collègues avec qui vous partager le registre) pourrez puller et pusher les images de votre registry depuis portainer simplement en spécifiant le bon tag dans portainer ou simplement en ligne de commande avec :

docker pull 172.20.0.5:5000/php-fpm-custom

UI pour le registry.

On a pas fait tout ça depuis l’IHM de Portainer car le module pour gérer les registres depuis portainer est payant (95$/an). Les autres options sont :

Bon mon besoin de collab étant limité, je vous laisse creuser le sujet par vous même.

Conclusion

Et voilà un TP de plus sur docker de plier, on a vu comment customiser un conteneur PHP-FPM dans docker et pousser l’image dans un registre privé. On arrive doucement au bout de cette série sur docker. Il me reste un dernier sujet sur le suivi des performances et de la consommation CPU/RAM des conteneurs et je crois qu’on sera au bout, sauf si vous avez des suggestions de trucs intéressants que j’aurais manqué d’ici là.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.