Contao & Docker

Docker est un outil incroyable pour le monde du développement. Grâce à sa logique de conteneur, formant des environnements spécifiques en un fichier de configuration, il permet de simuler des infrastructures de production sur nos postes de développement, ce qu’on peut apparenter à une machine virtuelle.
Grâce à ce système, on met en place des tests, unitaires ou/et d’intégration, qui ont pour objectif de valider toutes les fonctionnalités que l’on développe, avec de nombreuses contraintes et sur des configurations différentes. On s’assure ainsi que rien ne casse lors de la livraison !
Dans cet article, nous allons voir comment mettre en place une image Docker pour Contao et quelques cas à la marge !
Nous ne ferons pas un tutoriel sur l’installation de Docker sur votre poste de travail, il y a tellement de possibilités que résumer ça nécessite un article dédié, que l’on fera peut-être un jour. En attendant, il existe de nombreuses documentations, dont celle officielle de Microsoft, ainsi que celle de Docker, pour configurer le WSL et Docker sur son Windows 10/11.
Lexique
Autant pour vous que pour moi, je vais faire un point sur les termes employés par Docker, que l’on utilise dans cet article.
On parle d’abord d’image Docker. Il s’agit vulgairement de la configuration d’un conteneur. Lorsque vous exécutez une image Docker, l’outil créé un conteneur à partir des instructions données par l’image. C’est dans cette image que vous indiquez également tout ce dont vous avez besoin pour travailler. (image = ISO/disque d’installation de Windows avec possibilité d’installer/configurer des logiciels/composants en même temps)
Puis, vous avez le conteneur. Il s’agit de l’image en mouvement, en quelque sorte. Vous pouvez lire ce qu’il s’y passe et accéder à vos applications que vous développez. Lorsque vous interrompez un conteneur, il est généralement détruit. À part les éléments mentionnés lors de la configuration, tout sera recréé lors de sa nouvelle exécution. (conteneur = votre PC sur lequel vous avez installé votre Windows)
Mise en place
Pour mettre en place notre environnement, nous avons créé 3 fichiers :
- Celui qui contient les variables d’environnements :
.env
- Celui qui contient la configuration de l’image :
docker-compose.yml
- Celui qui contient les instructions de création :
DockerFile
Commençons par le commencement, le fichier .env
!
Variables d’environnement
Dans ce fichier, vous allez mettre toutes les variables propres à votre projet. Vous pouvez en enlever et en rajouter à votre convenance, c’est globalement ce qu’on cherche à modifier une fois qu’on a fait les deux autres fichiers.
La raison de ce fichier, c’est que réécrire des variables dans des fichiers de configuration peut occasionner des erreurs de syntaxe bêtes. Si vous n’avez qu’un endroit où modifier ce qui change, cela réduit considérablement le risque d’erreurs.
# Project name
COMPOSE_PROJECT_NAME=syncrobot
COMPOSE_PROJECT_NAME_SHORT=sc
PRJ_NAME='syncrobot'
PHP_VERSION='8.2'
CONTAO_VERSION='4.13'
APP_SECRET='YOUR APP SECRET' # MODIFY THIS
# Database settings
# MODIFY THIS
DB_HOST='my db host'
DB_DATABASE='my db'
DB_USER='my db user'
DB_PASSWORD='my db password'
DB_ROOT_PASSWORD='my root db password'
DATABASE_URL="mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:3306/${DB_DATABASE}" #Yes, 3306, because inside docker network, the internal ports are useable, not the exposed ones
# Directories settings
WORKDIR_BASE='/var/www/html'
WORKDIR_INIT="${WORKDIR_BASE}/init"
WORKDIR_CONTAO="${WORKDIR_BASE}/${PRJ_NAME}"
WORKDIR_BUNDLE_END_SLASH="${WORKDIR_BUNDLE}/"
# Contao settings
BASE_URL=your.base.url
BUNDLE_VERSION="^1.0" # can be changed for any composer type version such as ^1.0
Variable | Description |
---|---|
COMPOSER_PROJECT_NAME | Nom du projet |
COMPOSER_PROJECT_NAME_SHORT | Version courte du nom du projet (utile pour des préfixes) |
PRJ_NAME | Nom du projet bis, peut être différent de celui ci-dessus |
PHP_VERSION | Version de PHP souhaitée |
CONTAO_VERSION | Version de Contao souhaitée |
APP_SECRET | Clé secrète utilisée par Contao |
DB_HOST | Hôte de la base de données |
DB_DATABASE | Nom de la base de données |
DB_USER | Utilisateur de la base de données |
DB_PASSWORD | Mot de passe de l’utilisateur ci-dessus |
DB_ROOT_PASSWORD | Mot de passe Root de la base de données |
DATABASE_URL | URL de connexion de la base de données |
WORKDIR_BASE | Répertoire de travail dans l’image |
WORKDIR_INIT | Répertoire d’initialisation dans l’image |
WORKDIR_CONTAO | Répertoire de Contao |
BASE_URL | URL où le projet sera accessible (pensez à le rendre accessible dans le fichier hosts de Windows si c’est en local) |
BUNDLE_VERSION | Version du bundle à importer |
docker-composer.yml
Ce fichier sert à configurer les différentes images que nous allons associer dans notre environnement.
Les images sont disponibles sur le site Docker Hub, c’est sur ce site que se trouvent toutes les configurations des images disponibles.
Les particularités de notre fichier, c’est le stockage des fichiers Contao, dans l’image synchrobot-php, avec les volumes. Notez également le choix du port 8888, pour éviter le port 80, parfois utilisé en local par d’autres logiciels.
Niveau base de données, on utilise aussi les volumes pour sauvegarder notre base, et éviter qu’elle soit recréée à chaque démarrage de notre conteneur.
Le reste est assez classique, on utilise nos différentes variables d’environnement comme configurations, et on associe nos deux éléments dans le network synchrobot-db
pour que les conteneurs puissent communiquer entre eux.
version: '3.8'
services:
syncrobot-php:
build:
context: web
args:
WORKDIR_CONTAO: ${WORKDIR_CONTAO}
PRJ_NAME: ${PRJ_NAME}
CONTAO_VERSION: ${CONTAO_VERSION}
PHP_VERSION: ${PHP_VERSION}
APP_SECRET: ${APP_SECRET}
BASE_URL: ${BASE_URL}
BUNDLE_VERSION: ${BUNDLE_VERSION}
environment:
PRJ_NAME: ${PRJ_NAME}
WORKDIR_CONTAO: ${WORKDIR_CONTAO}
HTTP_HOST: ${BASE_URL}
container_name: ${COMPOSE_PROJECT_NAME_SHORT}_php_base
volumes:
- ./files:${WORKDIR_CONTAO}/files
networks:
- syncrobot-db
ports:
- 8888:80
syncrobot-db:
image: mysql:5.7
ports:
- 3306:3306
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} #mandatory
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
container_name: ${COMPOSE_PROJECT_NAME_SHORT}_db_base
volumes:
- ./database:/var/lib/mysql
networks:
- syncrobot-db
networks:
syncrobot-db:
Notez que comme la base de données est persistante, la création des utilisateurs MySQL ne se fera qu’à la création ! Donc si vous faites des modifications dans votre configuration, cela ne sera pris en compte qu’à la recréation de la base de données. Heureusement, il existe des astuces pour ça, comme passer par le fichier DockerFile directement, même si c’est moins pratique.
DockerFile
Ce fichier est le script qui se lance une fois le conteneur lancé et la configuration appliquée. Voilà notre fichier avec les détails de chaque ligne en commentaire.
# Récupération des variables d'environnement
ARG PHP_VERSION
FROM php:${PHP_VERSION}-apache
ARG CONTAO_VERSION
ARG WORKDIR_CONTAO
ARG APP_SECRET
ARG BASE_URL
ARG BUNDLE_VERSION
# On installe tout ce dont Contao a besoin
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
libicu-dev \
zip \
unzip \
libzip-dev \
libxml2-dev \
libgmp-dev \
re2c \
libmhash-dev \
file \
git \
iputils-ping \
cron \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl \
&& docker-php-ext-configure pdo \
&& docker-php-ext-install pdo \
&& docker-php-ext-configure pdo_mysql \
&& docker-php-ext-install pdo_mysql\
&& docker-php-ext-configure gmp \
&& docker-php-ext-install gmp \
&& docker-php-ext-configure zip \
&& docker-php-ext-install zip
# On installe Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# On récupère une clef SSH qui a accès à notre compte Github, pour pouvoir travailler sur nos repos
ADD bot_github_prod /ssh/github_key
ADD bot_github_prod.pub /ssh/github_key.pub
# On créé le répertoire de Contao et on attribue les droits à l'utilisateur www-data
# N'utilisez jamais le root !
RUN echo WORKDIR_CONTAO : $WORKDIR_CONTAO
RUN mkdir -p $WORKDIR_CONTAO \
# We give the www-data the same user UUID as ours
&& chown -R www-data:www-data /usr/local/bin/composer \
&& chown -R www-data:www-data /ssh/ \
&& chmod +x /usr/local/bin/composer \
&& chown -R www-data:www-data $WORKDIR_CONTAO \
&& chown -R www-data:www-data /var/www
# On ajoute une autorisation d'accès dans le répertoire public de notre répertoire Contao
RUN sed -i -e "s@DocumentRoot .*@DocumentRoot $WORKDIR_CONTAO/public@" -e "s@#ServerName www.example.com@ServerName $BASE_URL@" /etc/apache2/sites-available/000-default.conf
# On utilise désormais l'utilisateur www-data
USER www-data
# On se déplace dans le répertoire Contao puis on installe le CMS avec la version voulue
# Puis on autorise l'origine github.com dans les hôtes connus
RUN cd $WORKDIR_CONTAO \
&& composer create-project contao/managed-edition $WORKDIR_CONTAO $CONTAO_VERSION \
&& mkdir ~/.ssh \
&& echo "Host github.com\n HostName github.com\n IdentityFile /ssh/github_key" > ~/.ssh/config \
&& cat ~/.ssh/config \
&& ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
# On modifie notre config Composer pour importer directement le bundle sur lequel on travaille
# Ce bundle est accessible uniquement grâce à la clef SSH importée plus haut
RUN cd $WORKDIR_CONTAO \
&& composer config repositories.bot '{"type": "vcs", "url": "git@github.com:Web-Ex-Machina/press-fsync-bot-bundle"}' \
&& composer require "webexmachina/press-fsync-bot-bundle:$BUNDLE_VERSION"
# Puis on télécharge le fichier Contao Manager et on donne sa propriété à www-data pour qu'on puisse l'exécuter
ADD --chown=www-data:www-data https://download.contao.org/contao-manager/stable/contao-manager.phar $WORKDIR_CONTAO/public/contao-manager.phar.php
# Enfin, on ajoute une autorisation de proxy
RUN echo "TRUSTED_PROXIES=REMOTE_ADDR\nHTTP_HOST=$BASE_URL\nSERVER_NAME=$BASE_URL\nSERVER_PORT=443\nAPP_SECRET=$APP_SECRET" > $WORKDIR_CONTAO/.env
Notez que ce ficher est générique et ne permet que d’installer un Contao basique avec un bundle spécifique. Vous pouvez le complexifier davantage en fonction de vos besoins.
Agir dans le container
Le principe d’un conteneur Docker est de fonctionner en circuit fermé et d’être relancé “de zéro” selon la configuration voulue. Cela veut donc dire que tout changement dans votre conteneur sera supprimé lors de son redémarrage. Pas hyper pratique pour développer, vous allez me dire.
Sauf que justement, c’est une logique qui pousse à la rigueur. Lorsque l’on développe, on travaille sur un dépôt git ou svn qui permet de versionner les répertoires de travail. On en avait parlé un peu dans cet article. Vu qu’on est censé commit — envoyer nos changements sur le dépôt distant — chaque soir, vous pouvez fermer le conteneur et récupérer votre travail via le dépôt GIT.
Par contre, lorsque vous faites tourner un conteneur sur votre poste, vous ne pouvez pas facilement éditer les fichiers à l’intérieur. Précisément parce que le conteneur fonctionne en circuit fermé, avec ses permissions sur les fichiers. Il existe bien évidemment des solutions.
Visual Studio Code
La solution la plus simple est d’utiliser l’IDE de Microsoft. Comme le WSL est géré par Windows, il est capable de se connecter directement à un conteneur Docker et peut agir à l’intérieur sans action additionnelle. Voici les différentes étapes de connexions.
Dans notre cas, le projet est accessible à l’adresse localhost:8888
. On retrouve tout ce qu’on attend de Contao, et notre dépôt de travail dans le dossier vendor/webexmachina
. Tout ce que l’on fait via Visual Studio Code est transmis au conteneur sans action supplémentaire.
Autres IDE
Si votre IDE ne permet pas de modifier directement les fichiers dans les conteneurs, sachez qu’il est possible de copier des fichiers “locaux” vers votre conteneur Docker.
Dans le cas d’un projet Contao, ce qui nous intéressent sont les bundles dans le dossier vendor/webexmachina
.
La première étape est de récupérer les fichiers en local, via un git clone
.
Ensuite, il ne vous reste plus qu’à taper dans votre interpréteur de commande :
docker cp ./src/ sc_php_base:/usr/local/apache2/htdocs/smartgear/vendor/webexmachina/press-fsync-bot-bundle/
Cela fera une copie du dossier /src
du dossier courant dans le dossier /usr/local/apache2/htdocs/smartgear/vendor/webexmachina/press-fsync-bot-bundle/
du conteneur sc_php_base
(le conteneur qui contient le code de notre projet)
Vous pouvez donc modifier vos fichiers locaux puis les copier vers votre conteneur pour tester vos changements. Cette méthode est la plus simple à utiliser bien qu’il soit rébarbatif de devoir lancer la commande manuellement à chaque fois que l’on désire tester des changements.
Faites toujours attention à l’utilisateur en cours, surtout quand vous accédez au conteneur via ligne de commande. Par exemple, un cache:warmup en tant que root va complètement casser votre Contao car tous les fichiers seront créés avec des permissions root. Connectez-vous au docker avec l’utilisateur www-data, avec la ligne de commande suivante : docker exec -it -u www-data sc_php_base /bin/bash
Problématiques
Mettre en place un environnement Docker n’est pas aisé. Il y a à la fois beaucoup et peu de documentation disponible en ligne. Cela est dû au fait qu’il n’y ait pas de méthode absolue, ou d’environnement de travail unique.
Il y a beaucoup de choses à penser lorsque l’on met en place une infrastructure. On l’oublie quand on a des hébergements qui s’occupent de tout. La création de l’environnement Docker implique de mettre son nez dans tout ce dont vous avez besoin en production, ce qui n’est pas une mauvaise chose en soi, mais qui reste chronophage.
Ensuite, il y a toute la notion de persistance de la donnée. Par défaut, un conteneur ne garde rien. Donc c’est à vous de définir ce que vous voulez garder, en fonction de vos besoins du moment (via des volumes). Souvent, vous trouverez des configurations d’exemple dans les dépôts sur lesquels vous travaillez. Ils sont à répliquer et à adapter à votre configuration.
Il y a énormément de choses à apprendre sur Docker et davantage de possibilités. On a parlé ici de mettre en place un environnement de travail, mais Docker n’a pas que cet intérêt. Il est aussi utilisé pour réaliser des tests divers et variés sur des environnements de production spécifiques. De plus, on peut directement déployer en production des images Docker, ce qui facilite les mises en ligne ou les mises à jour d’applications.
Chez Web ex Machina, nous n’avons pas vraiment eu le besoin de cet outil jusqu’à récemment. Comme il est chronophage, il est naturellement plus adapté pour les gros projets, dans une optique de mises à jour régulières. Au final, nous commençons même à l’utiliser pour des projets plus simples. Avec la pratique, cela ne prend plus autant de temps, renforce nos méthodes de travail et nos procédures en interne, tout bénéf !
Dans la même catégorie