Mode opératoire — Monter un cluster Galera à 3 nœuds

Document autonome. Partie 1 théorique, partie 2 pas-à-pas appliqué à l’infrastructure sio.internal.

Prérequis : trois machines identiques — voir MO-1-Clonage-VM.md Dernière mise à jour : 27/09/2026


Sommaire

§Contenu
1Théorie — ce qu’est Galera, et ce qu’il n’est pas
2Réplication synchrone, certification, quorum
3SST, IST, et les quatre ports
4Pas à pas — préparer les trois nœuds
5Pas à pas — le fichier de configuration
6Pas à pas — amorcer le cluster
7Validation et tests
8Exploitation courante et pièges

1 · Théorie — Galera n’est pas une machine

C’est la confusion la plus fréquente, et il faut l’écarter d’emblée.

   UN RÉPARTITEUR INTERCEPTE          GALERA COORDONNE
   ─────────────────────────          ────────────────
   client ─► proxy ─► serveur A       nœud 1 ◄══╗
                   └─► serveur B      nœud 2 ◄══╬══ pair-à-pair
                                      nœud 3 ◄══╝
   il est SUR le chemin               rien ne s'intercale
   → il lui faut sa propre machine    → AUCUNE machine supplémentaire

Galera est une bibliothèque de réplication intégrée à MariaDB : /usr/lib/galera/libgalera_smm.so. Elle est déjà installée avec le paquet mariadb-server — on la voit défiler à l’installation :

Paramétrage de galera-4 (26.4.23-0+deb13u1) ...

On ne l’installe donc pas : on l’active par un fichier de configuration posé sur chaque nœud.

La règle générale : un composant qui intercepte du trafic (proxy, pare-feu, répartiteur) a besoin d’exister quelque part sur le chemin — il se dessine comme une boîte. Un composant qui coordonne des serveurs entre eux (réplication, cluster, grappe) vit à l’intérieur de ces serveurs — il se dessine comme des flèches entre des boîtes existantes.

1.1 Ce que Galera apporte, et ce qu’il n’apporte pas

Sans GaleraAvec Galera
Un disque meurt données perdues deux copies restantes
Un serveur s’arrête service interrompu les autres continuent
L’application s’en aperçoit— oui, sauf répartiteur devant

Résilience des données ≠ disponibilité du service. Galera protège la donnée. Pour que l’application ne s’aperçoive de rien, il faut un répartiteur devant — voir MO-3-HAProxy.md. C’est une distinction que les jurys apprécient.


2 · Réplication synchrone, certification, quorum

2.1 Synchrone vs asynchrone

   ASYNCHRONE (réplication MySQL classique)
   ────────────────────────────────────────
   maître : valide  ──► répond au client
        └─► envoie aux esclaves (plus tard)
   → si le maître meurt maintenant : transaction PERDUE

   SYNCHRONE (Galera)
   ──────────────────
   nœud : soumet aux autres ──► tous acceptent ──► valide ──► répond au client
   → la transaction existe partout AVANT que le client ne soit informé

Conséquence directe : une écriture sur un nœud est immédiatement lisible sur les autres. Pas de délai de rattrapage, pas de lecture périmée.

2.2 La certification

Avant de valider, le nœud soumet la transaction aux autres pour certification : le contrôle qu’aucune transaction concurrente ne modifie les mêmes lignes ailleurs.

   nœud 1 modifie la ligne 42  ─┐
                                ├─ au même instant → CONFLIT
   nœud 2 modifie la ligne 42  ─┘   l'un des deux reçoit une erreur de verrou

C’est pour cela qu’on n’écrit jamais sur plusieurs nœuds à la fois. L’application — WordPress, GLPI — ne sait pas gérer une erreur de certification : elle affichera une erreur à l’utilisateur.

La configuration canonique envoie toutes les écritures sur un seul nœud, les autres étant en attente de bascule. On parle de haute disponibilité active/passive pour les écritures, même si les trois nœuds en sont techniquement capables.

2.3 Le quorum — pourquoi trois et pas deux

   3 nœuds, 1 tombe  →  2 survivants sur 3  =  MAJORITÉ  →  écritures autorisées 
   2 nœuds, 1 tombe  →  1 survivant  sur 2  =  50 %      →  écritures REFUSÉES  

Avec deux nœuds, le survivant ne peut pas savoir si son partenaire est mort ou simplement injoignable. S’il continuait seul alors que l’autre en fait autant de son côté, on obtiendrait deux bases qui divergent : le split-brain, irréparable sans sacrifier des données.

Le cluster préfère donc s’arrêter d’écrire plutôt que risquer la divergence. Il passe en état non-Primary.

Deux nœuds n’apportent aucune disponibilité supplémentaire, seulement une copie des données. Le premier nombre utile est trois, et on reste toujours sur un nombre impair.


3 · SST, IST, et les quatre ports

3.1 Deux façons de rattraper un nœud

SST (State Snapshot Transfer)IST (Incremental State Transfer)
Quoicopie complète de la baseseulement les transactions manquées
Quandnœud neuf, ou répertoire de données videnœud absent quelques minutes
Duréeminutes à heures selon la taillequasi instantané
Port44444568

C’est précisément pour forcer un SST qu’on vide /var/lib/mysql sur un clone : on veut une copie cohérente prise à l’instant de la jonction, pas une base figée au moment du clonage.

3.2 Choisir la méthode de SST

MéthodeFonctionnementLe donneur pendant ce temps
rsynccopie brute des fichiers bloqué en lecture seule
mariabackupsauvegarde à chaud, cohérente continue de servir

mariabackup est la méthode canonique : l’application reste disponible pendant que les nouveaux nœuds se synchronisent. Elle exige le paquet mariadb-backup sur tous les nœuds — chacun peut devenir donneur ou receveur.

3.3 Les quatre ports

PortRôle
3306connexions des clients — le seul que le pare-feu verra
4567communication du groupe : découverte, votes, transactions (TCP et UDP)
4568IST — rattrapage incrémental
4444SST — copie complète

Si les trois nœuds sont dans le même VLAN — le cas de ce TP — aucune règle de pare-feu n’est nécessaire : le trafic est commuté et ne traverse pas le routeur. C’est un choix d’architecture qui a pour conséquence d’échapper au filtrage. À expliciter plutôt qu’à masquer : « on ne filtre pas ce qui ne passe pas par le routeur ».

Créer quand même un alias PORTS_GALERA documente les ports employés et prépare le jour où les nœuds seraient répartis sur plusieurs sites.


4 · Pas à pas — préparer les trois nœuds

Contexte appliqué : srv-mysql-01 10.0.20.10 (détient les données WordPress), srv-mysql-02 10.0.20.11 et srv-mysql-03 10.0.20.12 (clones, répertoire de données vidé — voir MO-1 §5). VLAN 20, Debian 13, MariaDB 11.8.6.

4.1 Accès Internet temporaire

Le VLAN BDD est volontairement coupé d’Internet. Rouvrir la règle de sortie le temps de l’installation, puis la refermer.

Vérification depuis un nœud :

sudo apt update

apt update est lui-même le test : s’il atteint les dépôts, la règle est ouverte. Inutile de chercher un autre outil — curl n’est pas forcément installé sur ces machines.

4.2 Installer mariadb-backup — sur les trois nœuds

sudo apt install -y mariadb-backup curl

Profiter de la fenêtre ouverte pour ajouter curl, utile au diagnostic. Après fermeture de la règle, plus aucun paquet ne pourra être téléchargé sans rouvrir.

4.3 Le compte de synchronisation — sur le nœud 1 uniquement

sudo mariadb -e "CREATE USER 'sst_user'@'localhost' IDENTIFIED BY '<mot-de-passe-sst_user>'; GRANT RELOAD, PROCESS, LOCK TABLES, BINLOG MONITOR ON *.* TO 'sst_user'@'localhost';"

Les nœuds 2 et 3 recevront ce compte par la synchronisation elle-même : Galera réplique aussi les tables système.

PrivilègeCe qu’il autorise
RELOADposer un verrou global cohérent le temps du cliché
PROCESSlire la liste des transactions en cours
LOCK TABLESverrouiller les tables non transactionnelles
BINLOG MONITORlire la position du journal binaire — le point de reprise

BINLOG MONITOR s’appelait REPLICATION CLIENT avant MariaDB 10.5 ; l’ancien nom reste accepté comme alias, mais les tutoriels qui l’emploient datent.

Surtout pas GRANT ALL, que donnent la moitié des guides en ligne. Un compte de service n’a que les privilèges de son service.

Vérification :

sudo mariadb -e "SHOW GRANTS FOR 'sst_user'@'localhost';"

5 · Pas à pas — le fichier de configuration

Une seule commande, à lancer telle quelle sur les trois nœuds. Les deux dernières lignes se remplissent toutes seules.

sudo tee /etc/mysql/mariadb.conf.d/60-galera.cnf > /dev/null <<EOF
[mysqld]
bind-address             = 0.0.0.0

[galera]
wsrep_on                 = ON
wsrep_provider           = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name       = galera-sio
wsrep_cluster_address    = gcomm://10.0.20.10,10.0.20.11,10.0.20.12

wsrep_sst_method         = mariabackup
wsrep_sst_auth           = sst_user:<mot-de-passe-sst_user>

binlog_format            = ROW
default_storage_engine   = InnoDB
innodb_autoinc_lock_mode = 2

wsrep_node_address       = $(ip -4 -br addr show ens18 | awk '{print $3}' | cut -d/ -f1)
wsrep_node_name          = $(hostname)
EOF

Le <<EOF sans guillemets autorise le shell à évaluer les $( ) avant d’écrire : chaque nœud inscrit sa propre adresse et son nom. Une seule commande pour trois machines, zéro risque de recopier la mauvaise valeur. (Avec <<'EOF' — guillemets simples — rien ne serait substitué. C’est la forme à utiliser quand on veut préserver des $ littéraux, par exemple ${APACHE_LOG_DIR} dans un VirtualHost.)

5.1 Les directives, une par une

DirectiveRôle
wsrep_onactive la réplication — l’interrupteur principal
wsrep_providerchemin de la bibliothèque Galera
wsrep_cluster_name identique sur tous les nœuds, sinon ils se rejettent
wsrep_cluster_addressla liste des membres — comment un nœud trouve les autres
wsrep_sst_methodmariabackup : le donneur reste disponible
wsrep_sst_authle compte créé au §4.3
wsrep_node_address / _namel’identité propre du nœud

5.2 Les trois directives qu’on oublie toujours

DirectivePourquoi elle est obligatoire
binlog_format = ROWGalera réplique les lignes modifiées, pas les requêtes. Un UPDATE … WHERE id = RAND() donnerait un résultat différent sur chaque nœud. Le mode ROW transmet le résultat, pas l’instruction.
default_storage_engine = InnoDBGalera ne réplique que l’InnoDB, transactionnel. Une table MyISAM ne serait pas répliquée, silencieusement.
innodb_autoinc_lock_mode = 2Sans cela, deux nœuds insérant simultanément attribueraient le même identifiant auto-incrémenté. Le mode 2 décale les plages par nœud.

5.3 Le renoncement sur bind-address

Galera impose d’écouter sur plusieurs ports : bind-address doit passer de l’adresse précise du serveur à 0.0.0.0.

C’est un assouplissement réel, à documenter comme tel. Il reste compensé par deux barrières :

VerrouOùToujours en place ?
1 · bind-address restreintle serveur abandonné
2 · règle de pare-feule routeur seule porte vers le VLAN 20
3 · GRANT … @'adresse'MariaDB origine vérifiée

Effet de bord bienvenu : les clones ont hérité du bind-address de leur source — une adresse qu’ils ne portent pas. MariaDB refuserait de démarrer avec Can't assign requested address. Comme 60-galera.cnf est lu après 50-server.cnf (ordre alphabétique), sa valeur écrase la précédente et corrige le problème au passage.

5.4 Vérifier

grep -E "wsrep_node_|bind-address" /etc/mysql/mariadb.conf.d/60-galera.cnf

Sur chaque nœud, les deux lignes wsrep_node_* doivent porter ses propres valeurs.


6 · Pas à pas — amorcer le cluster

6.1 L’ordre est impératif

# sur le nœud qui DÉTIENT LES DONNÉES, et lui seul
sudo systemctl stop mariadb
sudo galera_new_cluster
# puis nœud 2 — attendre « Synced » — ENSUITE nœud 3
sudo systemctl start mariadb
sudo systemctl enable mariadb

6.2 galera_new_cluster ne se lance qu’une fois, sur un seul nœud

   galera_new_cluster  →  « je suis la semence, mes données font référence »  → CRÉE le cluster
   systemctl start     →  « je cherche un cluster existant »                  → le REJOINT

L’exécuter sur deux nœuds produirait deux clusters distincts portant le même nom, chacun convaincu d’être le vrai : le split-brain, irréparable sans choisir quelles données sacrifier.

Le nœud amorceur est celui qui détient les données — ici srv-mysql-01, qui héberge la base WordPress.

6.3 Un nœud à la fois

Deux SST simultanés font travailler le donneur deux fois, sans gain. Attendre l’état Synced du nœud 2 avant de démarrer le nœud 3.

Pour suivre en direct :

sudo journalctl -u mariadb -f

Les états traversés : Joiner (réception du SST) → Synced (à jour). Côté donneur, on observe Donor/Desynced pendant la copie.

systemctl enable à ne pas oublier sur les nœuds 2 et 3 : ils avaient été désactivés parce que leur répertoire de données était vide (MO-1 §5). Sans cela, un redémarrage de VM sortirait le nœud du cluster sans prévenir.


7 · Validation et tests

7.1 L’état du cluster — sur les trois nœuds

sudo mariadb -e "SHOW STATUS WHERE Variable_name IN ('wsrep_cluster_size','wsrep_cluster_status','wsrep_local_state_comment','wsrep_incoming_addresses');"

Résultat attendu, identique partout :

| wsrep_local_state_comment | Synced                                 |
| wsrep_incoming_addresses  | 10.0.20.11:0,10.0.20.12:0,10.0.20.10:0 |
| wsrep_cluster_size        | 3                                      |
| wsrep_cluster_status      | Primary                                |
VariableSignification
wsrep_cluster_sizenombre de membres vus par ce nœud — les trois doivent dire 3
wsrep_cluster_statusPrimary = cette partition détient le quorum
wsrep_local_state_commentSynced = ce nœud est à jour
wsrep_incoming_addressesla liste des membres, vue par ce nœud

Primary ne signifie pas « nœud principal » — c’est l’état de la partition. Tous les nœuds d’un cluster sain sont Primary simultanément.

Interroger les trois nœuds, pas un seul. Un nœud isolé du groupe afficherait wsrep_cluster_size = 1 en toute bonne foi. La cohérence se vérifie en croisant les réponses.

7.2 Le test de réplication

Sur le nœud 2 :

sudo mariadb -e "CREATE DATABASE test_replication; CREATE TABLE test_replication.preuve (id INT PRIMARY KEY, note VARCHAR(50)); INSERT INTO test_replication.preuve VALUES (1,'ecrit sur le noeud 2');"

Sur le nœud 3 :

sudo mariadb -e "SELECT * FROM test_replication.preuve;"

La ligne doit s’y trouver immédiatement. Nettoyage :

sudo mariadb -e "DROP DATABASE test_replication;"

7.3 Le test qui impressionne : la réplication des comptes

Créer un utilisateur sur le nœud 1 :

sudo mariadb -e "CREATE USER 'demo'@'10.0.10.10' IDENTIFIED BY 'x';"

Le retrouver sur le nœud 3 :

sudo mariadb -e "SELECT user, host FROM mysql.global_priv WHERE user='demo';"

Plus parlant qu’une table de démonstration : ce ne sont pas des données applicatives mais les tables système de MariaDB. Galera réplique tout le serveur, comptes et privilèges compris. 40-replication-comptes-et-site.png

40-replication-comptes-et-site

7.4 Le test du quorum — le plus formateur

Corrigé le 02/11/2026 : un arrêt propre ne fait PAS perdre le quorum. Avec systemctl stop, le nœud prévient les autres qu’il part : les survivants recalculent la majorité entre eux et restent Primary, même à un seul (c’est ce qui s’est passé dans H-39). Le quorum ne se perd que si des nœuds disparaissent sans prévenir : panne, ou coupure réseau. On simule donc une coupure : la carte réseau des deux nœuds est débranchée dans Proxmox.

Dans Proxmox, pour le nœud 2 puis le nœud 3 : Hardware → Network Device (net0) → Edit → cocher Disconnect. En ligne de commande sur l’hyperviseur, l’équivalent (en reprenant toute la ligne net0 lue par qm config <vmid>, sinon on perd les autres réglages de la carte) :

qm set <vmid> --net0 virtio=<MAC>,bridge=vmbr1,tag=20,link_down=1

Sur le survivant :

sudo mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_status';"
sudo mariadb -e "CREATE DATABASE test_quorum;"

Attendu : non-Primary, et l’écriture refusée.

C’est contre-intuitif, et c’est tout l’intérêt. On s’attend à ce qu’un système « tienne » le plus longtemps possible. Or le survivant refuse délibérément d’écrire : ne détenant plus la majorité, il ne peut pas savoir s’il est le dernier debout ou simplement isolé du reste. Il préfère s’arrêter plutôt que produire une base qui divergerait de celle des autres.

Rebrancher les deux cartes (décocher Disconnect, ou la même commande sans link_down=1) : le cluster se reforme seul, sans galera_new_cluster.

Validé le 02/11/2026 : non-Primary, wsrep_ready OFF, CREATE DATABASE refusé par ERROR 1047 … WSREP has not yet prepared node for application use ; site en 503 pendant la panne ; après rebranchement, 3 / Primary / Synced sur les trois nœuds en moins de 10 s (capture 145).

Effet de bord à connaître : tout ce dont la base est dans le cluster s’arrête avec lui, y compris Grafana et donc les alertes (H-66).


8 · Exploitation courante et pièges

8.1 Arrêt complet du cluster — le cas qui piège

Si les trois nœuds sont arrêtés, aucun ne redémarrera seul : chacun cherchera un cluster qui n’existe plus.

Il faut ré-amorcer depuis le nœud le plus à jour. Pour l’identifier :

sudo cat /var/lib/mysql/grastate.dat
seqno:              1234
safe_to_bootstrap:  1
ChampLecture
seqnonuméro de la dernière transaction — le plus élevé gagne
safe_to_bootstrap: 1ce nœud s’est arrêté en dernier, il peut amorcer

Sur ce nœud uniquement : sudo galera_new_cluster, puis démarrer les autres normalement.

Ne jamais forcer safe_to_bootstrap à 1 sur un nœud qui affiche 0 sans avoir comparé les seqno. Ce serait choisir arbitrairement quelles transactions perdre.

8.2 Les pièges rencontrés

SymptômeCauseCorrection
Can't connect … through socketle service n’a pas été démarrésystemctl start mariadb
Can't assign requested addressbind-address hérité du clone60-galera.cnf avec 0.0.0.0
SST échoue · wsrep_sst_mariabackup: No such filemariadb-backup absent sur un nœudl’installer partout
Access denied for user 'sst_user'mot de passe erroné dans wsrep_sst_authvérifier la concordance
failed to reach primary viewle nœud amorceur n’est pas joignable sur 4567vérifier le réseau
journalctl : No journal files were foundmachine-id changé après le bootsystemctl restart systemd-journald

8.3 Commandes de diagnostic à connaître

# état complet
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_%';"

# les cinq variables qui comptent
sudo mariadb -e "SHOW STATUS WHERE Variable_name IN ('wsrep_cluster_size','wsrep_cluster_status','wsrep_local_state_comment','wsrep_connected','wsrep_ready');"

# qui est dans le groupe
sudo mariadb -e "SHOW STATUS LIKE 'wsrep_incoming_addresses';"

# le journal
sudo journalctl -u mariadb -n 50 --no-pager

8.4 Checklist de montage

   Trois machines, identités régénérées (MO-1)
   /var/lib/mysql vidé sur les futurs joignants
   mariadb-backup installé sur LES TROIS
   Compte sst_user créé sur le nœud amorceur
   60-galera.cnf posé sur les trois, valeurs propres vérifiées
   galera_new_cluster sur UN SEUL nœud — celui qui a les données
   Nœuds 2 puis 3, UN À LA FOIS, attendre « Synced »
   systemctl enable mariadb sur les nœuds 2 et 3
   wsrep_cluster_size = 3 vérifié sur LES TROIS
   Test de réplication croisée
   Accès Internet du VLAN refermé

À retenir en une phrase : Galera ne se déploie pas, il s’active — et le seul moment délicat est l’amorçage, qui n’a lieu qu’une fois, sur un seul nœud, celui qui détient la vérité.