etcd : Architecture et fonctionnement

Module R57

Dalibo SCOP

24.09

29 août 2024

Sur ce document

Formation Module R57
Titre etcd : Architecture et fonctionnement
Révision 24.09
PDF https://dali.bo/r57_pdf
EPUB https://dali.bo/r57_epub
HTML https://dali.bo/r57_html
Slides https://dali.bo/r57_slides
TP https://dali.bo/r57_tp
TP (solutions) https://dali.bo/r57_solutions

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 12 à 16.

etcd : Architecture et fonctionnement

Au menu

  • L’algorithme Raft
  • Implémentation Raft dans etcd
  • Installation etcd
  • Fonctionnalités d’etcd
  • Tâches d’administrations d’un cluster etcd

L’algorithme Raft

  • Algorithme de consensus
  • Replicated And Fault Tolerant
  • Leader-based requests

Raft : Journal et machine à états

  • Machine à états : leader, follower ou candidate
  • Journal des événements :
    • répliqué depuis le leader
    • même résultat sur tous les nœuds
  • Mandats :
    • commence par une élection du leader (unique)
    • numérotés, croissants

Élection d’un leader

  • Heart beats depuis le leader vers les followers
  • Si pas de nouvelles du leader :
    • démarrage de l’élection d’un nouveau leader
  • Promotion par consensus entre les membres
  • Si échec de l’élection, attente aléatoire
  • Tolérance de panne à partir de 3 nœuds

Réplication du journal

  • Mécanisme de réplication
  • Structure des journaux
  • Protection contre les incohérences
    • n° de mandat + index

Sécurité & cohérence

Lors d’une élection:

  • les votants refusent tout candidat en retard par rapport à eux

Majorité et tolérance de panne

  • Nombre impair de nœuds total recommandé
  • Majorité : quorum = (nombre de nœuds / 2) + 1
  • Tolérance de panne : nombre de nœuds - quorum
  • Pas de quorum : pas de réponse au client

Tolérance de panne : Tableau récapitulatif

Nombre de nœuds Majorité Tolérance de panne
2 2 0
3 2 1
4 3 1
5 3 2
6 4 2
7 4 3
8 5 3

Interaction avec les clients

  • Toutes les communications passent par le leader
  • Protection contre l’exécution en double des requêtes
  • Le leader valide les entrées non commitées après son élection
  • Le leader vérifie qu’il est bien leader avant de répondre à une demande de lecture

Raft en action

Démo interactive :

Mécanique d’etcd

  • Serveur de stockage distribué par consensus
    • clé/valeur
  • Multiples nœuds
  • Nécessite 3 nœuds minimum pour avoir une tolérance de panne
  • Haute disponibilité et tolérance de panne
  • Élection par un quorum

etcd V2 et V3

  • Abandon de l’API REST au profit de gRPC
  • endpoints différents pour la supervision
  • Commandes différentes dans etcdctl (ETCDCTL_API)
  • Nouvelles fonctionnalités (ou implémentations différentes):
    • transactions
    • leases
    • quorum & lecture linéarisées / sérialisées
  • Possibilité d’activer le protocole v2 :
    • deux bases de données séparées, une par version de l’API
  • Utilisez l’API v3
    • supportée par Patroni depuis la version 2.0.0 (septembre 2020)

etcd et Raft

  • Implémente l’algorithme Raft
    • hautement disponible: élections et réplication par consensus
    • tolérance de panne possible qu’à partir de 3 nœuds
    • différence : requêtes sur un followers
  • Nombre de membres impair, recommandé entre 3 et 7
  • Mutualisation du cluster etcd pour plusieurs clusters Patroni

Modes de défaillance d’etcd

  • Indisponibilité :
    • du leader
    • d’un nombre de membres inférieur ou égal à la tolérance de panne
    • d’un nombre de membres supérieur à la tolérance de panne
  • Partition réseau
  • Échec lors de l’initialisation du cluster (bootstrap)

Mise en œuvre d’etcd

Contraintes matérielles et logicielles

  • VMs dédiées !
  • Dimensionner la mémoire pour les données + l’OS
    • quota par défaut : 2 Go (largement supérieur à ce que Patroni utilise)
    • préconisation : 2 à 8 Go
    • attention à l’overcommit / OOM killer
  • Des disques rapides pour ne pas ralentir le cluster lors des COMMIT
    • utiliser du SSD
    • tester le stockage avec fio
  • Un réseau fiable (beaucoup d’échanges entre nœuds etcd)
  • Exemple chez CoreOS : proc dual core, 2 Go de RAM, 80 Go de SSD.

Installation des binaires

  • RedHat/EL depuis le dépôt PGDG :
    • dnf install etcd
    • firewalld
  • Debian/Ubuntu :
    • apt-get install etcd (Debian 11)
    • apt-get install etcd-server etcd-client (Debian 12)
  • Installation depuis les sources (Github)

Configuration etcd

Trois méthodes de configuration différentes:

  • En arguments à l’exécutable etcd
  • En variables d’environnement lues par l’exécutable etcd
  • Dans un fichier YAML pointé --config-file

Services etcd

Configurations employées par les principaux services etcd:

  • Service etcd.service
  • Variables d’environnements…
  • … chargées depuis un fichier :
    • /etc/etcd/etcd.conf (paquet PGDG Red Hat & dérivées)
    • /etc/default/etcd (Debian et dérivées)
  • Installation manuelle
    • créer le fichier de service
    • adapter la configuration

Démarrage du cluster

  • systemctl start etcd
    • attente du quorum dès démarrage
  • Premier contact avec etcdctl
  • Création automatique du data-dir

Utilisation d’etcd

Stockage distribué

  • Manipulation des clés avec : get, put, del (ou l’API)
  • Anciennes versions des clés accessibles… jusqu’au passage d’une purge
  • Lectures linéarisées et sérialisées
  • Patroni utilise etcd comme serveur de configurations distribuées pour :
    • stocker des informations sur l’état du cluster
    • stocker la configuration dynamique de Patroni

Notion de bail

  • Notion de lease dans etcd
    • associe une durée de validité (TTL) à une clé
    • le client peut renouveler le bail
    • etcd détruit la clé à l’expiration du bail
  • Utilisation par Patroni
    • permet d’identifier le leader Patroni et de garantir que la leader key expire une fois le TTL expiré

Unicité des clés

  • Création d’une transaction (etcdctl txn)
  • Création conditionnelle d’une clé
    • action si la clé n’existe pas
    • action si la clé existe
  • Permet à Patroni de garantir qu’il n’y a qu’un seul leader

Maintenances

Authentification

  • Activation de l’authentification requise
    • etcdctl auth enable
  • user : pour l’authentification
    • etcdctl user [add|del|get|list]
    • etcdctl user [grant-role|revoke-role]
  • role : conteneur pour les droits, assigné aux utilisateurs
    • etcdctl role [add|del|get|list]
    • etcdctl role [grant-permission|revoke-permission]

Chiffrement des communications

  • Communications avec les clients :
    • --cert-file
    • --key-file
    • --client-cert-auth
    • --trusted-ca-file
  • Communications au sein du cluster etcd :
    • --peer-cert-file
    • --peer-key-file
    • --peer-client-cert-auth
    • --peer-trusted-ca-file

Sauvegarde et restauration

  • Nécessité de recréer le cluster
  • Sauvegarde des données
    • etcdctl … snapshot save …
    • copie de la base de données ($ETCD_DATA_DIRECTORY/member/snap/db)
  • Restauration
    • nouveau cluster
    • etcdctl snapshot restore …
  • Démarrer le nouveau cluster

Remplacement de membre

Pour remplacer un membre sans risquer de perdre le quorum :

  • d’abord retirer l’ancien membre
  • puis ajouter le nouveau membre
  • et jamais l’inverse !

Autres tâches de maintenance

  • Journal Raft et espace de stockage :
    • rétention
    • quota
    • compactage manuelle et automatique

Supervision et métrologie

  • endpoint /debug
  • endpoint /metrics
    • destiné à prometheus
    • Grafana dispose d’une source de données Prometheus
    • surveiller
      • présence d’un leader, nombre d’élections
      • statistiques sur les consensus, performances du stockage et du réseau
      • l’utilisation du quota
  • endpoint /health

Questions

  • C’est le moment !

Quiz

Travaux pratiques

Raft

Nous allons utiliser le simulateur Raftscope.

Les 5 nœuds portent tous le dernier numéro de mandat qu’ils ont connu. Le leader est cerclé de noir.

Le timeout de chaque follower se décrémente en permanence et est réinitialisé quand un message de heart beat du leader est reçu.

Le journal de chaque nœud est visible sur la droite pour suivre la propagation des informations de chaque request.

Il est possible de mettre en pause, d’accélérer ou ralentir.

Les actions se font par clic droit sur chaque nœud :

  • stop / resume / restart pour stopper/(re)démarrer un nœud ;
  • time out sur un nœud provoque une élection ;
  • request est une interrogation client (à faire uniquement sur le leader).
  • Observer la première élection et l’échange des heart beats par la suite.
  • Mettre en défaut le leader (stop) et attendre une élection.
  • Lancer plusieurs écritures (requests) sur le leader.
  • Remettre en route l’ancien leader.
  • Arrêter deux nœuds, dont le leader, et observer le comportement du cluster.
  • Qu’en est-il de la tolérance de panne ?
  • Arrêter un nœud secondaire (pour un total de 3 nœuds arrêtés).
  • Tester en soumettant des écritures au primaire.
  • Rallumer un nœud pour revenir à 3 nœuds actifs dont un leader.
  • Éteindre le leader. Tenter de soumettre des écritures.
  • Que se passe-t-il ?

Installation d’etcd sous Debian

  • Installer etcd sur les 3 nœuds e1, e2 et e3.
  • Supprimer le nœud etcd créé sur chaque serveur.
  • Configurer un cluster etcd sur les 3 nœuds e1, e2 et e3.
  • Démarrez le cluster etcd

Installation d’etcd sous Rocky Linux 9

  • Installer etcd sur les 3 nœuds e1, e2 et e3.
  • Configurer un cluster etcd sur les 3 nœuds e1, e2 et e3.
  • Activez et démarrez le cluster etcd

etcd : manipulation (optionnel)

Ces exercices utilisent l’API v3 d’etcd.

But : manipuler la base de données distribuée d’Etcd.

  • Depuis un nœud, utiliser etcdctl put pour écrire une clef foo à la valeur bar.
  • Récupérer cette valeur depuis un autre nœud.
  • Modifier la valeur à baz.
  • Créer un répertoire food contenant les clés/valeurs poisson: bar et vin: blanc.
  • Récupérer toutes les clefs du répertoire food en exigeant une réponse d’un quorum.

But : constater le comportement d’Etcd conforme à l’algorithme Raft.

  • Tout en observant les logs de etcd et la santé de l’agrégat, procéder au fencing du leader avec virsh suspend <nom machine>.
  • Geler le nouveau leader de la même manière et voir les traces du nœud restant.

Travaux pratiques (solutions)

Raft

  • Observer la première élection et l’échange des heart beats par la suite.

Les nœuds portent au départ le numéro de mandat 1, il n’y a pas de leader :

élection etcd - étape 1

Il faut attendre que l’un des nœuds ait atteint son timeout pour qu’il propose une élection. Ici, c’est le nœud S2 qui déclenche l’élection :

élection etcd - étape 2

Les petites pastilles sur ce nœud S2 représentent le nombre de votes lui étant favorable. Un vote sur cinq est pour le moment validé : le sien. Les autres nœuds de l’agrégat reçoivent donc la candidature de S2 et y répondent tous favorablement :

élection etcd - étape 3

Nous voyons le nombre de vote augmenter au fur et à mesure que S2 les reçoit :

élection etcd - étape 4

Finalement, S2 remporte l’élection, crée le mandat n°2 et envoie son premier message de keep alive :

élection etcd - étape 5

Les autres se raccrochent à lui et entretiennent chacun leur time out.

  • Mettre en défaut le leader (stop) et attendre une élection.

Le même phénomène se produit et l’on arrive au mandat 3. Ici, le timeout du nœud S1 expire en premier :

failover etcd - étape 1

S1 déclenche une élection :

failover etcd - étape 2

Les autres nœuds accordent leur vote à S1, sauf S2 qui est éteint :

failover etcd - étape 3

S1 devient leader :

failover etcd - étape 4
  • Lancer plusieurs écritures (requests) sur le leader.

Elles apparaissent sur la droite dans le journal au fur et à mesure que le leader les diffuse. La diffusion se fait en plusieurs étapes. Écrite et émission depuis S1 :

Requête etcd - étape 1

Bonne réception des nœuds S3, S4 et S5 :

Requête etcd - étape 2

S0 ayant reçu une majorité d’acquittement, il valide la valeur auprès des autres nœuds :

Requête etcd - étape 3

Tous les nœuds ont validé la valeur :

Requête etcd - étape 4
  • Remettre en route l’ancien leader.

Celui-ci redémarre à 2 (en tant que follower) :

failback etcd - étape 1

Il bascule sur le mandat 3 au premier heart beat reçu, et commence à remplir son journal :

failback etcd - étape 2

Il rattrape ensuite son journal avec autant d’échange avec le leader que nécessaire :

failback etcd - étape 3 failback etcd - étape 4 failback etcd - étape 5

  • Arrêter deux nœuds, dont le leader, et observer le comportement du cluster.
  • Qu’en est-il de la tolérance de panne ?

Le quorum demeure au sein du cluster, il est donc toujours possible de déclencher une élection. Comme précédemment, les trois nœuds restants s’accordent sur un leader. Dans notre exemple, tous les nœuds déclenchent leur propre élection en même temps :

second failover etcd - étape 1

Chaque nœud ayant voté pour lui-même, il n’y a pas de consensus sur le nœud à élire, les nœuds redeviennent followers. L’un d’entre eux voit son timeout atteint, ce qui donne lieu à une seconde élection :

second failover etcd - étape 2

Elle conduit ici à l’élection du nœud S2 :

second failover etcd - étape 3

La tolérance de panne est maintenant nulle.

  • Arrêter un nœud secondaire (pour un total de 3 nœuds arrêtés).
  • Tester en soumettant des écritures au primaire.

Le cluster continue de fonctionner : on peut lui soumettre des écritures (requests) :

perte quorum etcd - étape 1

Elles sont bien répliquées mais ne sont pas exécutées (ou commitées) par le leader :

perte quorum etcd - étape 2

Pour cela, il faut que les écritures aient été répliquées vers la majorité des nœuds du cluster. Cela signifie que le client reste en attente de confirmation du traitement de sa demande.

  • Rallumer un nœud pour revenir à 3 nœuds actifs dont un leader.
  • Éteindre le leader. Tenter de soumettre des écritures.
  • Que se passe-t-il ?

L’un des deux nœuds survivants lance une élection :

Tentative d’élection sans quorum etcd - étape 1

L’autre le suit :

Tentative d’élection sans quorum etcd - étape 2

Mais comme le quorum de 3 nœuds (moitié de 5 plus 1) n’est pas obtenu, l’élection échoue. Les time out continuent d’expirer et de nouvelles élections sont lancées :

Tentative d’élection sans quorum etcd - étape 3

Faute de leader, il devient impossible de soumettre des écritures. Tout client s’appuyant dessus reçoit une erreur. Il faut attendre le retour en ligne d’un nœud et l’élection d’un nouveau leader.

Installation d’etcd sous Debian

  • Installer etcd sur les 3 nœuds e1, e2 et e3.

Les paquets etcd sont disponibles dans les dépôts officiels de Debian 12. L’installation consiste simplement à installer les deux paquets etcd-server et etcd-client :

# apt-get install -y etcd-server etcd-client
  • Supprimer le nœud etcd créé sur chaque serveur.

Afin de respecter la politique des paquets Debian, l’installation du paquet etcd-server crée automatiquement une instance etcd locale. Nous devons la détruire avant de pouvoir construire notre cluster etcd à trois nœuds.

Sur chaque serveur etcd, exécuter les commandes suivantes :

# systemctl stop etcd.service
# rm -Rf /var/lib/etcd/default
  • Configurer un cluster etcd sur les 3 nœuds e1, e2 et e3.

La configuration sous Debian se situe dans le fichier /etc/default/etcd où doivent être renseignés les paramètres etcd sous leur forme de variables d’environnements.

Voici le fichier de configuration commenté du nœud e1, veillez à adapter toutes les adresses IP 10.x.y.z :

# nom du nœud au sein du cluster
ETCD_NAME=e1

# emplacement du répertoire de données
ETCD_DATA_DIR=/var/lib/etcd/acme

# interface et port d'écoute des autres nœuds
ETCD_LISTEN_PEER_URLS=http://10.0.0.11:2380

# interfaces et port d'écoute des clients
ETCD_LISTEN_CLIENT_URLS=http://10.0.0.11:2379,http://127.0.0.1:2379,http://[::1]:2379

# interface et port d'écoute à communiquer aux clients
ETCD_ADVERTISE_CLIENT_URLS=http://10.0.0.11:2379

#######################################
## Initialisation du cluster et du nœud

# création du nœud au sein d'un nouveau cluster
ETCD_INITIAL_CLUSTER_STATE=new

# interface et port à communiquer aux autres nœuds
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://10.0.0.11:2380

# liste des nœuds composant le cluster
ETCD_INITIAL_CLUSTER=e1=http://10.0.0.11:2380,e2=http://10.0.0.12:2380,e3=http://10.0.0.13:2380
  • Démarrez le cluster etcd

Une fois les trois fichiers de configuration établis, nous pouvons démarrer le cluster en exécutant la commande suivante sur tous les serveurs etcd :

# systemctl start etcd

La commande suivante doit désormais fonctionner sur n’importe quel nœud :

$ etcdctl -wjson endpoint status | jq
[
  {
    "Endpoint": "127.0.0.1:2379",
    "Status": {
      "header": {
        "cluster_id": 11628162814576028000,
        "member_id": 13786016400334385000,
        "revision": 95,
        "raft_term": 24
      },
      "version": "3.4.23",
      "dbSize": 61440,
      "leader": 2266733444126347800,
      "raftIndex": 112,
      "raftTerm": 24,
      "raftAppliedIndex": 112,
      "dbSizeInUse": 53248
    }
  }
]

L’état du cluster est visible grace à la commande suivante :

$ etcdctl endpoint status -w table --cluster
+-----------------------+------------------+---------+---------+-----------+[..]+--------+
|       ENDPOINT        |        ID        | VERSION | DB SIZE | IS LEADER |[..]| ERRORS |
+-----------------------+------------------+---------+---------+-----------+[..]+--------+
| http://10.0.0.11:2379 | 9e80988e833ccb43 |  3.5.13 |   20 kB |     false |[..]|        |
| http://10.0.0.13:2379 | a10d8f7920cc71c7 |  3.5.13 |   29 kB |      true |[..]|        |
| http://10.0.0.12:2379 | abdc532bc0516b2d |  3.5.13 |   20 kB |     false |[..]|        |
+-----------------------+------------------+---------+---------+-----------+[..]+--------+

Installation d’etcd sous Rocky Linux 9

  • Installer etcd sur les 3 nœuds e1, e2 et e3.

Les paquets etcd sont disponibles depuis les dépôts PGDG pour les distributions Red Hat 9 & dérivées (comme ici Rocky Linux 9). Il nous faut donc au préalable configurer ce dépôt :

# dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/\
pgdg-redhat-repo-latest.noarch.rpm

Il est désormais possible d’installer le paquet etcd en activant le dépôt pgdg-rhel9-extras :

# dnf --enablerepo=pgdg-rhel9-extras install -y etcd
  • Configurer un cluster etcd sur les 3 nœuds e1, e2 et e3.

La configuration sur cette distribution se situe dans le fichier /etc/etcd/etcd.conf où sont renseignés les paramètres etcd sous leur forme de variables d’environnements.

Ci-après les différents paramètres à modifier pour le nœud e1, veillez à adapter toutes les adresses IP 10.x.y.z :

ETCD_NAME=e1
ETCD_DATA_DIR=/var/lib/etcd/acme
ETCD_LISTEN_PEER_URLS=http://10.0.0.11:2380
ETCD_LISTEN_CLIENT_URLS=http://10.0.0.11:2379,http://127.0.0.1:2379,http://[::1]:2379
ETCD_ADVERTISE_CLIENT_URLS=http://10.0.0.11:2379
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://10.0.0.11:2380
ETCD_INITIAL_CLUSTER=e1=http://10.0.0.11:2380,e2=http://10.0.0.12:2380,e3=http://10.0.0.13:2380
  • Activez et démarrez le cluster etcd

Une fois les trois fichiers de configuration établis, nous pouvons démarrer le cluster en exécutant la commande suivante sur tous les serveurs etcd :

# systemctl start etcd

Afin qu’etcd démarre automatiquement avec le serveur, il est nécessaire d’activer le service :

# systemctl enable etcd

Une fois les trois fichiers de configuration établis, la commande suivante doit fonctionner sur n’importe quel nœud :

$ etcdctl -wjson endpoint status | jq
[
  {
    "Endpoint": "127.0.0.1:2379",
    "Status": {
      "header": {
        "cluster_id": 11628162814576028000,
        "member_id": 13786016400334385000,
        "revision": 95,
        "raft_term": 24
      },
      "version": "3.4.23",
      "dbSize": 61440,
      "leader": 2266733444126347800,
      "raftIndex": 112,
      "raftTerm": 24,
      "raftAppliedIndex": 112,
      "dbSizeInUse": 53248
    }
  }
]

L’état du cluster est visible grace à la commande suivante :

$ etcdctl endpoint status -w table --cluster
+-----------------------+------------------+---------+---------+-----------+[..]+--------+
|       ENDPOINT        |        ID        | VERSION | DB SIZE | IS LEADER |[..]| ERRORS |
+-----------------------+------------------+---------+---------+-----------+[..]+--------+
| http://10.0.0.11:2379 | 9e80988e833ccb43 |  3.5.13 |   20 kB |     false |[..]|        |
| http://10.0.0.13:2379 | a10d8f7920cc71c7 |  3.5.13 |   29 kB |      true |[..]|        |
| http://10.0.0.12:2379 | abdc532bc0516b2d |  3.5.13 |   20 kB |     false |[..]|        |
+-----------------------+------------------+---------+---------+-----------+[..]+--------+

etcd : manipulation (optionnel)

Ces exercices utilisent l’API v3 d’etcd.

But : manipuler la base de données distribuée d’Etcd.

  • Depuis un nœud, utiliser etcdctl put pour écrire une clef foo à la valeur bar.
$ etcdctl put foo bar
OK
  • Récupérer cette valeur depuis un autre nœud.
$ etcdctl get foo
foo
bar
  • Modifier la valeur à baz.
$ etcdctl put foo baz
OK
  • Créer un répertoire food contenant les clés/valeurs poisson: bar et vin: blanc.
$ etcdctl put food/poisson bar
OK

$ etcdctl put food/vin blanc
OK

$ etcdctl get --keys-only --prefix food/
food/poisson

food/vin
  • Récupérer toutes les clefs du répertoire food en exigeant une réponse d’un quorum.
$ etcdctl get --consistency="l" --keys-only --prefix food/
 /food/poisson

 /food/vin

But : constater le comportement d’Etcd conforme à l’algorithme Raft.

  • Tout en observant les logs d’etcd et la santé de l’agrégat, procéder au fencing du leader avec virsh suspend <nom machine>.

Le leader peut être identifié avec la commande suivante :

# etcdctl -wtable --endpoints http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379 endpoint status

Dans notre correctif, e1 est actuellement leader. Dans une fenêtre sur e2 et e3, laisser défiler le journal :

# journalctl -fu etcd

Depuis une session dans le serveur hôte, interroger e2 ou e3 continuellement à propos de la santé de l’agrégat avec par exemple :

$ watch -n1 "curl -s -XGET http://10.0.0.12:2379/health | jq"
{
  "health": "true",
}

Depuis le serveur hôte, cette commande interrompt brutalement la machine virtuelle e1 (mais sans la détruire) :

# virsh destroy e1
Domain 'e1' destroyed

Il est aussi possible de suspendre la machine avec la commande suivante :

# virsh suspend e1
Domain 'e1' suspended

La commande inverse est alors virsh resume e1.

Notez que la machine est suspendue, donc encore présente, mais plus du tout exécutée par l’hyperviseur. Cette présence inactive peut parfois créer des situations déstabilisantes pour les autres machines virtuelles ayant toujours des connexions TCP en suspend. Aussi, après son réveil, sauf présence de chrony ou ntpsec, l’horloge de cette machine virtuelle nécessite une intervention manuelle afin de la resynchroniser.

Dans les traces de e3, nous trouvons :

INFO: 49fc71338f77c1c4 is starting a new election at term 3
INFO: 49fc71338f77c1c4 became candidate at term 4
INFO: 49fc71338f77c1c4 received MsgVoteResp from 49fc71338f77c1c4 at term 4
INFO: 49fc71338f77c1c4 [logterm: 3, index: 9] sent MsgVote request to 97e570ef03022438 at term 4
INFO: 49fc71338f77c1c4 [logterm: 3, index: 9] sent MsgVote request to be3b2f45686f7694 at term 4
INFO: raft.node: 49fc71338f77c1c4 lost leader be3b2f45686f7694 at term 4

L’identifiant 49fc71338f77c1c4 est celui de e3 lui-même. Ces traces nous indiquent :

  • le déclenchement de l’élection avec un nouveau mandat n°4 ;
  • le vote de e3 pour lui-même ;
  • les demandes de vote vers e1 et e2.
  • la perte du leader e1 (identifiant be3b2f45686f7694) durant le mandat n°4

Suivent alors les messages suivants:

INFO: 49fc71338f77c1c4 received MsgVoteResp from 97e570ef03022438 at term 4
INFO: 49fc71338f77c1c4 has received 2 MsgVoteResp votes and 0 vote rejections
INFO: 49fc71338f77c1c4 became leader at term 4
INFO: raft.node: 49fc71338f77c1c4 elected leader 49fc71338f77c1c4 at term 4

Seul e2 (ici 97e570ef03022438) répond au vote, mais cette réponse suffit à atteindre le quorum (de 2 sur 3) et valider l’élection de e3 comme nouveau leader.

En interrogeant l’état de e3, nous confirmons bien qu’il est leader :

$ etcdctl -wtable endpoint status
+----------------+------------------+---------+---------+-----------+-[…]
|    ENDPOINT    |        ID        | VERSION | DB SIZE | IS LEADER | […]
+----------------+------------------+---------+---------+-----------+-[…]
| 127.0.0.1:2379 | 49fc71338f77c1c4 |  3.4.23 |   20 kB |      true | […]
+----------------+------------------+---------+---------+-----------+-[…]
  • Geler le nouveau leader de la même manière et voir les traces du nœud restant.

L’état de l’agrégat tombe en erreur suite à cette perte du quorum :

$ curl -s -XGET http://10.0.0.12:2379/health | jq
{
  "health": "false"
}

Dans les traces de e2, nous constatons qu’il tente en boucle une élection, envoie des messages mais faute de réponse, n’obtient jamais d’accord pour l’élection :

15:36:31 INFO: 97e570ef03022438 is starting a new election at term 4
15:36:31 INFO: 97e570ef03022438 became candidate at term 5
15:36:31 INFO: 97e570ef03022438 received MsgVoteResp from 97e570ef03022438 at term 5
15:36:31 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to 49fc71338f77c1c4 at term 5
15:36:31 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to be3b2f45686f7694 at term 5
15:36:31 INFO: raft.node: 97e570ef03022438 lost leader 49fc71338f77c1c4 at term 5
15:36:33 INFO: 97e570ef03022438 is starting a new election at term 5
15:36:33 INFO: 97e570ef03022438 became candidate at term 6
15:36:33 INFO: 97e570ef03022438 received MsgVoteResp from 97e570ef03022438 at term 6
15:36:33 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to 49fc71338f77c1c4 at term 6
15:36:33 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to be3b2f45686f7694 at term 6
15:36:34 INFO: 97e570ef03022438 is starting a new election at term 6
15:36:34 INFO: 97e570ef03022438 became candidate at term 7
15:36:34 INFO: 97e570ef03022438 received MsgVoteResp from 97e570ef03022438 at term 7
15:36:34 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to 49fc71338f77c1c4 at term 7
15:36:34 INFO: 97e570ef03022438 [logterm: 4, index: 1192] sent MsgVote request to be3b2f45686f7694 at term 7

La situation revient à la normale dès qu’un des deux autres revient en ligne avec par exemple la commande virsh start e3.