Mettre en place WordPress en haute disponibilité avec Docker Swarm, GlusterFS et MariaDB Galera

WordPress haute disponibilité Docker Swarm - interface Dokploy

Table des matières

  1. GlusterFS : stockage partagé
  2. Cluster MariaDB Galera
  3. Stack WordPress (Swarm via Dokploy)
  4. Exposition publique (Cloudflare Tunnel)
  5. Vérifications et test de bascule

Architecture & Nœuds

HostnameRôle SwarmRôle DB
node-managerManager
node-worker-1WorkerGalera node 1
node-worker-2WorkerGalera node 2
node-worker-3WorkerGalera node 3

1. GlusterFS : stockage partagé

Pourquoi GlusterFS ?

Sans stockage partagé, chaque réplica WordPress a ses propres fichiers. Un upload d’image sur le réplica 1 ne serait pas visible depuis le réplica 2. GlusterFS crée un volume distribué monté sur tous les nœuds, tous les réplicas voient exactement les mêmes fichiers en temps réel.

Installation sur les 3 workers

apt install glusterfs-server -y
systemctl enable --now glusterd

Création du cluster

Depuis worker-1 uniquement, déclarer les pairs :

gluster peer probe IP_WORKER2
gluster peer probe IP_WORKER3
gluster peer status

Création du volume répliqué

# Créer le dossier brique sur chaque worker
mkdir -p /gluster/wordpress

# Créer le volume depuis worker-1
gluster volume create wordpress replica 3 \
  IP_WORKER1:/gluster/wordpress \
  IP_WORKER2:/gluster/wordpress \
  IP_WORKER3:/gluster/wordpress \
  force

gluster volume start wordpress
gluster volume status wordpress

replica 3 signifie que chaque fichier est répliqué sur les 3 briques simultanément. Si un nœud tombe, GlusterFS bascule automatiquement vers les autres.

Montage sur chaque worker

mkdir -p /mnt/gluster/wordpress
mount -t glusterfs IP_LOCALE:/wordpress /mnt/gluster/wordpress

Ajouter dans /etc/fstab pour le montage automatique au démarrage :

IP_WORKER:/wordpress /mnt/gluster/wordpress glusterfs defaults,_netdev 0 0

2. Cluster MariaDB Galera

Principe

  • 3 instances MariaDB synchronisées en temps réel
  • Chaque conteneur WordPress se connecte à la DB locale via 172.17.0.1 (bridge Docker de l’hôte)
  • Si un nœud tombe, les 2 autres continuent de fonctionner

Installation sur les 3 workers

apt install -y mariadb-server mariadb-client galera-4

Configuration Galera

Créer /etc/mysql/mariadb.conf.d/galera.cnf sur chaque worker, adapter wsrep_node_name et wsrep_node_address par nœud :

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0

# Galera Provider
wsrep_on=ON
wsrep_provider=/usr/lib/libgalera_smm.so
wsrep_cluster_name="galera-cluster"
wsrep_cluster_address="gcomm://IP_WORKER1,IP_WORKER2,IP_WORKER3"

# Adapter par nœud
wsrep_node_name="worker-1"       # worker-2 / worker-3
wsrep_node_address="IP_WORKER1"  # IP_WORKER2 / IP_WORKER3

wsrep_sst_method=rsync

Bootstrap du cluster

# Sur worker-1 UNIQUEMENT
systemctl stop mariadb
galera_new_cluster

# Sur les autres workers
systemctl start mariadb

Vérification

mysql -u root -e "SHOW STATUS LIKE 'wsrep_cluster_size';"

Création de la base WordPress

Sur worker-1 uniquement, réplication automatique vers les autres :

CREATE DATABASE wpdb;
GRANT ALL PRIVILEGES ON wpdb.* TO 'wpdb_usr'@'%' IDENTIFIED BY '<MOT_DE_PASSE>';
FLUSH PRIVILEGES;

3. Stack WordPress (Swarm via Dokploy)

Services déployés

ServiceImageReplicasPlacement
wordpresswordpress:latest3node.role == worker
cloudflaredcloudflare/cloudflared:latest3

Variables d’environnement WordPress

WORDPRESS_DB_HOST=172.17.0.1
WORDPRESS_DB_USER=wpdb_usr
WORDPRESS_DB_PASSWORD=<MOT_DE_PASSE>
WORDPRESS_DB_NAME=wpdb

172.17.0.1 est le bridge Docker local, chaque réplica se connecte à l’instance MariaDB Galera de son propre hôte, sans trafic inter-nœuds pour les requêtes DB.

Volume partagé

/mnt/gluster/wordpress:/var/www/html

Labels Traefik

deploy:
  replicas: 3
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.wordpress.rule=Host(`monsite.com`)"
    - "traefik.http.routers.wordpress.entrypoints=web"
    - "traefik.http.services.wordpress.loadbalancer.server.port=80"
    - "traefik.docker.lbswarm=true"
    - "traefik.http.middlewares.wp-close.headers.customresponseheaders.Connection=close"
    - "traefik.http.routers.wordpress.middlewares=wp-close"
  placement:
    constraints:
      - node.role == worker

4. Exposition publique (Cloudflare Tunnel)

Architecture

Internet → Cloudflare → cloudflared (3 réplicas) → Traefik → WordPress

Chaque réplica cloudflared utilise le même token, Cloudflare enregistre chaque instance comme un connecteur distinct et bascule automatiquement si l’un tombe. Aucun port entrant à ouvrir sur les serveurs.

Configuration du service

  • Image : cloudflare/cloudflared:latest
  • Arguments : tunnel --no-autoupdate run
  • Variable d’env : TUNNEL_TOKEN=<TOKEN>
  • Replicas : 3

Route Cloudflare Zero Trust

Dans Zero Trust → Networks → Tunnels → Public Hostnames :

DomaineService
monsite.comhttp://nom-service-wordpress:80

5. Vérifications et test de bascule

Vérifier la réplication GlusterFS

Uploader une image depuis WordPress (Médias → Ajouter) puis vérifier sur les 3 workers :

ls /mnt/gluster/wordpress/wp-content/uploads/

Test de bascule Swarm

# Simuler la panne d'un worker
docker node update --availability drain node-worker-1

# Vérifier la redistribution des réplicas
docker service ps nom-service-wordpress | grep Running

# Remettre le nœud en service
docker node update --availability active node-worker-1

Commandes GlusterFS utiles

gluster volume status wordpress   # état du volume
gluster volume info wordpress     # info détaillée
gluster peer status               # état des pairs
gluster volume heal wordpress info # vérifier la synchronisation

Récapitulatif HA

ComposantRedondance
Application WordPress3 réplicas Swarm
Stockage fichiersGlusterFS répliqué sur 3 nœuds
Base de donnéesMariaDB Galera multi-master (3 nœuds)
Tunnel Cloudflare3 connecteurs cloudflared