Assembler Docker, Traefik, mkcert et WordPress
Je continue mon apprentissage de Docker en ajoutant Traefik. Dans mon précédent article, j’installais WordPress avec Docker Compose, mais comme je le précisais l’installation était basique. Il restait des choses à améliorer, comme l’accès en HTTPS. De plus, la communication avec d’autres outils semblait ne pas fonctionner. Pour que l’utilisation d’un conteneur soit vraiment avantageux, il fallait améliorer ça. Comment s’y prendre ?
Résumons le projet
Dans le précédent article, nous avons vu comment installer WordPress avec Docker et docker-compose. Cependant, en procédant ainsi, nous ne pouvions pas accéder au site en HTTPS. Pour développer des thèmes et plugins, il serait également intéressant de pouvoir utiliser Gulp et BrowserSync. Je souhaite ici avoir une installation locale de WordPress pour faire du développement.
Je ne vais pas revenir en détail sur l’installation de WordPress et des conteneurs annexes (PHPMyAdmin, MySQL) ; consultez plutôt le précédent article si vous le souhaitez. Ici, je vais avant tout m’attarder sur la configuration de notre conteneur, Traefik, associé à mkcert pour du développement local. Évidemment, je reviendrais sur la configuration globale pour vous expliquer les changements entre le précédent article et celui-ci.
Au final, nous accéderons à :
- WordPress avec l’adresse
www.docker-wordpress.test
- PHPMyAdmin avec l’adresse
pma.docker-wordpress.test
- Traefik avec l’adresse
traefik.docker-wordpress.test
Vous pouvez choisir un autre nom de domaine ; pensez simplement à le modifier dans les prochaines étapes également. Sauf erreur, il s’agit uniquement de la création et de la déclaration des certificats ainsi que le domaine établi dans le fichier .env
et la configuration de BrowserSync.
Étape 1 : générer un certificat avec mkcert
Dans un précédent article, je vous expliquais la création d’un virtualhost sur Manjaro donc je ne vais pas revenir dessus. Par contre, pensez à ajouter également les sous-domaines dans le fichier /etc/hosts
.
Pour obtenir un certificat local avec mkcert, procédez comme ceci.
- Installons mkcert sur Manjaro :
sudo pacman -S mkcert
- Créons une autorité de confiance local :
mkcert -install
- Créons un répertoire qui contiendra nos certificats locaux (le nom est arbitraire) :
mkdir ./certs/
- Générons le certificat pour docker-wordpress.test (un nom de domaine local) :
mkcert -cert-file ./certs/docker-wordpress.test.pem -key-file ./certs/docker-wordpress.test-key.pem docker-wordpress.test "*.docker-wordpress.test"
Maintenant que nos certificats sont prêts, passons à l’étape suivante.
Étape 2 : configurer Traefik avec Docker
Qu’est-ce que Traefik ?
Traefik est un proxy inverse (« reverse proxy » en anglais) et un équilibreur de charge (« load balancer » en anglais) écrit en Golang, créé par Émile Vauge et distribué par Traefik Labs. Il va intercepter et acheminer les demandes entrantes vers notre site. Il détecte immédiatement le service déployé et met à jour les règles de routage en temps réel.
Traefik utilise deux fichiers de configuration différents. Le premier définit la configuration statique qui est lue au démarrage du processus ; il faut redémarrer le service à chaque changement. Le second définit la configuration dynamique ; elle indique comment traiter les requêtes et les changements se font dynamiquement.
Comment le configurer ?
Nous allons avoir besoin de trois choses : deux fichiers de configuration pour Traefik et ajouter le service dans docker-compose.yml
. Nous placerons les fichiers de configuration de Traefik dans un dossier du même nom pour plus de clarté : mkdir traefik
.
Le fichier de configuration statique
Dans sa documentation, Traefik propose un exemple de fichier de configuration pour l’utiliser avec Docker. Je vais donc me baser sur celui-ci et lui apporter quelques modifications. Concernant le format, vous avez le choix entre YAML et TOML, c’est selon votre préférence ; ici j’utiliserai un fichier YAML : touch traefik/traefik.yml
. Voici son contenu :
global:
checkNewVersion: true
sendAnonymousUsage: false
log:
level: INFO
api:
insecure: false
dashboard: true
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
watch: true
network: dwp-proxy
exposedByDefault: false
file:
filename: /etc/traefik/ssl.yml
watch: true
Je pense que la configuration globale et celle des logs parlent d’elles-mêmes. Concernant l’api
:
insecure: true
permet d’exposer l’API sur le point d’entréetraefik
(ou sur le port 8080 s’il n’existe pas). Ici, nous ne voulons pas utiliser ce port mais un sous-domaine, donc il faut remplacertrue
parfalse
.dashboard: true
permet d’activer le tableau de bord
Ensuite, passons à la configuration des points d’entrée :
- nous définissons deux points d’entrée (HTTP et HTTPS)
- nous appliquons une redirection de
http
vershttps
- pour chaque point d’entrée, nous définissons une adresse ; elle correspond au numéro de port utilisé (80 pour HTTP / 443 pour HTTPS)
Enfin, concernant les fournisseurs (providers
), nous définissons :
- Docker avec :
watch
qui permet d’indiquer à Traefik de surveiller ce fournisseurs.network
qui permet de spécifier le réseau Docker à utiliser. Ici, nous utiliserons un réseau spécifique (dwp-proxy
) pour les conteneurs communiquant avec Traefik.exposedByDefault: false
qui indique à Traefik d’ignorer tous les conteneurs sauf ceux qui ont un label l’autorisant.
- notre fichier de configuration dynamique avec
watch
pour le surveiller etfilename
pour spécifier son emplacement.
Le fichier de configuration dynamique
Nous créons un fichier de configuration dans le dossier traefik
: touch traefik/ssl.yml
. Voici son contenu :
tls:
certificates:
- certFile: "/etc/certs/docker-wordpress.test.pem"
keyFile: "/etc/certs/docker-wordpress.test-key.pem"
Évidemment, si vous avez utilisé un autre nom de domaine pour générer les certificats, il faut penser à le changer. Il n’est pas possible d’utiliser de variables d’environnement ici…
De même, il n’est pas possible de les déclarer dans notre fichier docker-compose.yml
comme le précise la documentation :
In the above example, we’ve used the file provider to handle these definitions. It is the only available method to configure the certificates (as well as the options and the stores).
Traefik : https://doc.traefik.io/traefik/https/tls/
L’ajout du service Traefik dans Docker Compose
Maintenant que nos fichiers de configuration sont prêts, il nous reste à configurer le service dans notre fichier docker-compose.yml
:
traefik:
image: traefik:${DWP_TRAEFIK_VERSION:-2.3.1}
container_name: dwp_traefik
restart: on-failure
ports:
- "127.0.0.1:80:80"
- "127.0.0.1:443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
- ./traefik/ssl.yml:/etc/traefik/ssl.yml
- ./certs:/etc/traefik/certs
networks:
- dwp-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.${DWP_DOMAIN_NAME}`)"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=${DWP_TRAEFIK_USER:-admin}:${DWP_TRAEFIK_PASSWORD:-admin}"
- "traefik.http.routers.traefik.tls=true"
Dans le précédent article, j’expliquais le rôle d’image
, restart
, ports
et volume
. Je ne vais pas revenir dessus. Cependant, pour volume
, voici les différentes choses à monter :
- le service Docker
- le fichier de configuration statique
- le fichier de configuration dynamique
- les certificats
Lors de la création du fichier de configuration statique, je vous ai parlé du réseau Docker. Nous attachons le service traefik à ce réseau (dwp-proxy
).
Viens la partie plus délicate, la configuration de Traefik au travers des labels
. Il est possible de faire la même chose (avec une autre syntaxe) dans le fichier de configuration dynamique, mais ce dernier ne prend pas en compte les environnements de variable. J’ai donc préféré définir la configuration ici :
- avec
traefik.enable
, nous autorisons Traefik à surveiller ce conteneur - ensuite, nous définissons le point d’entrée (
https
) - puis, nous définissons l’adresse de Traefik
- il faut également ajouter le service
api@internal
pour le tableau de bord de Traefik - puis, nous indiquons que l’accès au tableau de bord nécessite des identifiants
- nous spécifions les identifiants à utiliser
- finalement, nous indiquons à Traefik que le routeur est uniquement dédié aux requêtes HTTPS
Pour générer les identifiants, choisissez un nom d’utilisateur et créez votre mot de passe avec la commande htpasswd
:
htpasswd -n nomUtilisateur
#output#New password:
#output#Re-type new password:
#output#nomUtilisateur:leMotDePasseEncrypté
Si vous n’utilisez pas les variables d’environnement, il faut dédoubler les $
du mot de passe pour échapper le caractère.
L’intégralité du fichier Docker Compose
Nous avons défini le service Traefik, mais les autres conteneurs doivent également être modifiés. Ainsi, nous supprimons les ports, nous ajoutons des labels et nous créons nos réseaux.
version: "3.8"
services:
db:
image: mysql:${DWP_MYSQL_VERSION:-5.7}
container_name: dwp_db
restart: on-failure
environment:
MYSQL_ROOT_PASSWORD: ${DWP_ROOT_PASSWORD:-root}
MYSQL_DATABASE: ${DWP_DB_NAME:-wordpress}
MYSQL_USER: ${DWP_DB_USER:-wordpress}
MYSQL_PASSWORD: ${DWP_DB_PASSWORD:-wordpress}
volumes:
- db_data:/var/lib/mysql
networks:
- dwp-web
wordpress:
depends_on:
- db
image: wordpress:${DWP_WORDPRESS_VERSION:-latest}
container_name: dwp_wordpress
restart: on-failure
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: ${DWP_DB_NAME:-wordpress}
WORDPRESS_DB_USER: ${DWP_DB_USER:-wordpress}
WORDPRESS_DB_PASSWORD: ${DWP_DB_PASSWORD:-wordpress}
WORDPRESS_TABLE_PREFIX: ${DWP_TABLE_PREFIX:-wp_}
working_dir: /var/www/html
volumes:
- ./wp-content:/var/www/html/wp-content
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
networks:
- dwp-proxy
- dwp-web
labels:
- "traefik.enable=true"
- "traefik.http.routers.wordpress.entrypoints=http,https"
- "traefik.http.routers.wordpress.rule=Host(`www.${DWP_DOMAIN_NAME}`) || Host(`${DWP_DOMAIN_NAME}`)"
- "traefik.http.routers.wordpress.tls=true"
pma:
depends_on:
- db
image: phpmyadmin:${DWP_PMA_VERSION:-latest}
container_name: dwp_pma
restart: on-failure
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: ${DWP_ROOT_PASSWORD:-root}
networks:
- dwp-proxy
- dwp-web
labels:
- "traefik.enable=true"
- "traefik.http.routers.pma.entrypoints=http,https"
- "traefik.http.routers.pma.rule=Host(`pma.${DWP_DOMAIN_NAME}`)"
- "traefik.http.routers.pma.tls=true"
traefik:
image: traefik:${DWP_TRAEFIK_VERSION:-2.3.1}
container_name: dwp_traefik
restart: on-failure
ports:
- "127.0.0.1:80:80"
- "127.0.0.1:443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/etc/traefik/traefik.yml
- ./traefik/ssl.yml:/etc/traefik/ssl.yml
- ./certs:/etc/traefik/certs
networks:
- dwp-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`traefik.${DWP_DOMAIN_NAME}`)"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=${DWP_TRAEFIK_USER:-admin}:${DWP_TRAEFIK_PASSWORD:-admin}"
- "traefik.http.routers.traefik.tls=true"
volumes:
db_data:
networks:
dwp-proxy:
name: dwp-proxy
dwp-web:
name: dwp-web
Voici ce qui change par rapport au précédent article :
- Deux réseaux sont crées en fin de fichier : l’un sert à notre proxy inverse Traefik et les conteneurs qu’il surveille, l’autre isole notre base de données de Traefik tout en la reliant aux conteneurs avec lesquels elle doit communiquer.
- J’ai ajouté un
container_name
pour plus de clarté. - Il faut ajouter des labels à nos conteneurs WordPress et PHPMyAdmin :
- nous commençons par activer le suivi Traefik,
- puis, nous définissons les points d’entrée (
http
ouhttps
), - ensuite, nous définissons l’adresse qui permettra d’y accéder,
- finalement, comme Traefik, nous indiquons que le routeur est uniquement dédié aux requêtes HTTPS.
- J’utilise des variables d’environnement avec certaines valeurs par défaut.
Étape 3 : Vérification de la configuration Docker-Traefik
Maintenant que Traefik est configuré, vérifions que tout fonctionne.
docker-compose up -d
En accédant à traefik.docker-wordpress.test
, vous devriez voir ça (après authentification) :
En accédant à pma.docker-wordpress.test
, vous devriez voir le formulaire de connexion à PHPMyAdmin :
En accédant à www.docker-wordpress.test
, vous devriez voir le formulaire d’installation de WordPress. Une fois la procédure terminé, votre site devrait fonctionner :
Grâce aux variables d’environnement, nous pouvons modifier quasiment toute notre configuration à partir du fichier .env
. Malheureusement, dans le fichier de configuration dynamique ce n’est pas possible de les utiliser, il faudra donc penser à remplacer le nom des certificats. Voici à quoi ressemble mon fichier :
# Global
DWP_DOMAIN_NAME=docker-wordpress.test
# MySQL
DWP_MYSQL_VERSION=5.7
DWP_ROOT_PASSWORD=password
# WordPress
DWP_WORDPRESS_VERSION=latest
DWP_DB_NAME=wordpress
DWP_DB_USER=wordpress
DWP_DB_PASSWORD=password
DWP_TABLE_PREFIX=dwp_
# PHPMyAdmin
DWP_PMA_VERSION=latest
# Traefik
DWP_TRAEFIK_VERSION=2.3.1
DWP_TRAEFIK_USER=admin
DWP_TRAEFIK_PASSWORD=$apr1$9yJz5uLe$kmI2.2Jn46PuXVg7IB5JS0
Une installation WordPress opérationnelle !
Désormais, votre installation locale fonctionnera aussi bien avec HTTP (qui est redirigé) qu’HTTPS. Le certificat est correctement détecté et utilisé, sans erreur ou avertissement. Vous pouvez donc développer vos thèmes et plugins !
Si vous utilisez Gulp avec BrowserSync, ça devrait fonctionner sans avoir à ajouter Node (ou d’autres conteneurs). Il faut, par contre, configurer les options correctement. Voici ce que j’utilise (dans un fichier de configuration séparé, à vous de l’adapter) :
// BrowserSync options
bsConfig: {
proxy: {
target: 'https://www.docker-wordpress.test',
},
hostname: 'docker-wordpress.test',
port: '8080',
open: 'local',
browserAutoOpen: false,
injectChanges: true,
ghostMode: {
scroll: true,
links: true,
forms: true,
},
snippetOptions: {
// Provide a custom Regex for inserting the snippet.
rule: {
match: /<\/body>/i,
fn: function(snippet, match) {
return snippet + match;
},
},
},
rewriteRules: [
{
match: /localhost:8080/g,
fn: function(req, res, match) {
return 'localhost:3000';
},
},
],
},
Quelques problèmes avant d’arriver au résultat
Finalement, une fois opérationnel, ça ne paraît pas si compliqué. Pourtant, j’ai eu quelques soucis avant d’arriver à ce résultat. Mon premier problème vient tout simplement de ma méconnaissance de Traefik ; c’est un outil nouveau pour moi. Mon deuxième problème se rapproche d’avantage de l’étourderie.
Je voulais utiliser des variables d’environnement pour que la configuration soit facilement réutilisable. De plus, je voulais déclarer la configuration dynamique dans un fichier séparé plutôt que de l’inclure dans docker-compose.yml
. Seulement, Traefik ne supporte pas les variables d’environnement dans la configuration dynamique… Il m’a fallu du temps pour comprendre que la plupart de mes problèmes venaient de là.
Enfin, j’ai longtemps cherché comment configurer l’accès aux sous-domaines, en vain. Puis, je me suis souvenu que mon fichier /etc/hosts
contenait seulement www.docker-wordpress.test
… Il fallait que je déclare également les sous-domaines.
Pour les deux articles, voici deux commandes qui m’ont été utiles pour résoudre mes problèmes :
# Vérifier que les volumes sont montés correctement :
docker-compose exec wordpress bash
# ou, pour Traefik :
docker-compose exec traefik /bin/sh
#output#
# Vérfier les logs de Traefik :
docker-compose logs traefik
Vous pouvez retrouver les fichiers sur mes dépôts Github et Gitlab accompagnés des étapes en anglais.
0 commentaire
Laisser un commentaire