etcd est le magasin de clés-valeurs distribué au cœur de chaque cluster Kubernetes, stockant tout l’état du cluster, des définitions de pods aux secrets. Lorsqu’etcd tombe en panne ou perd des données, l’intégralité du plan de contrôle cesse de fonctionner. Ce guide vous accompagne dans le déploiement d’etcd en tant que service autonome et en tant que cluster à trois nœuds, sa sécurisation avec le TLS mutuel, la création et la restauration de snapshots, ainsi que la compréhension de son utilisation par Kubernetes — afin que vous puissiez l’exploiter en toute confiance en production.
Prérequis
- Serveur(s) Linux sous Ubuntu 22.04 ou version ultérieure (un pour le nœud unique, trois pour le cluster)
- Accès root ou sudo
- Familiarité de base avec la gestion des services systemd
curlettarinstallés- Pour TLS :
cfsslouopenssldisponible - Ports 2379 (client) et 2380 (pair) ouverts entre les nœuds etcd
Qu’est-ce qu’etcd et comment fonctionne-t-il
etcd est un magasin de clés-valeurs distribué open source, fortement cohérent, initialement développé par CoreOS et désormais un projet diplômé de la Cloud Native Computing Foundation (CNCF). Il utilise l’algorithme de consensus Raft pour s’assurer que tous les nœuds s’accordent sur l’état actuel, même en cas de partitions réseau ou de pannes de nœuds.
Les propriétés clés à comprendre :
- Cohérence forte : chaque lecture retourne la dernière écriture validée, jamais une valeur obsolète
- API Watch : les clients s’abonnent aux changements de clés et reçoivent des notifications en temps réel
- Transactions atomiques : les opérations compare-and-swap permettent de construire des verrous distribués
- Baux (Leases) : les clés peuvent expirer automatiquement, permettant l’élection de leader basée sur des heartbeats
Kubernetes s’appuie sur etcd pour chaque élément de l’état du cluster. Le serveur API est le seul composant qui lit et écrit directement dans etcd — tous les autres composants (scheduler, controller manager, kubelet) communiquent via le serveur API.
| Fonctionnalité | etcd | Redis | Consul | ZooKeeper |
|---|---|---|---|---|
| Consensus | Raft | Aucun (autonome) | Raft | ZAB |
| Cohérence forte | Oui | Non (éventuelle) | Oui | Oui |
| API Watch | Oui | Pub/sub uniquement | Oui | Oui |
| Natif Kubernetes | Oui | Non | Non | Non |
| TLS intégré | Oui | Optionnel | Oui | Optionnel |
| Complexité opérationnelle | Faible | Très faible | Moyenne | Élevée |
etcd s’impose pour Kubernetes car il a été conçu spécifiquement pour les cas d’usage du plan de contrôle : petites valeurs, taux de lecture élevé, écritures peu fréquentes, et exactitude plutôt que débit brut.
Installation d’etcd
Téléchargez la dernière version depuis le dépôt officiel GitHub. Au moment de la rédaction, la série 3.5.x est la version stable recommandée pour Kubernetes 1.29+.
ETCD_VER=v3.5.12
DOWNLOAD_URL=https://github.com/etcd-io/etcd/releases/download
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \
-o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcd /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdutl /usr/local/bin/
etcd --version
etcdctl version
Créez le répertoire de données et un utilisateur système dédié :
sudo groupadd --system etcd
sudo useradd -s /sbin/nologin --system -g etcd etcd
sudo mkdir -p /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd
Génération des Certificats TLS
Ne faites jamais tourner etcd sans TLS dans un environnement autre qu’un ordinateur portable local. etcd stocke des secrets et des identifiants — tout écouteur non chiffré représente un risque de sécurité immédiat.
Installez cfssl :
curl -Lo /usr/local/bin/cfssl \
https://github.com/cloudflare/cfssl/releases/latest/download/cfssl_linux-amd64
curl -Lo /usr/local/bin/cfssljson \
https://github.com/cloudflare/cfssl/releases/latest/download/cfssljson_linux-amd64
chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson
Créez une CA et un certificat serveur. Enregistrez ce qui suit sous ca-config.json :
{
"signing": {
"default": { "expiry": "87600h" },
"profiles": {
"etcd": {
"expiry": "87600h",
"usages": ["signing","key encipherment","server auth","client auth"]
}
}
}
}
Générez les certificats CA et serveur :
# CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# Certificat serveur + pair (ajoutez toutes les IPs/noms d'hôtes des nœuds dans le tableau hosts du CSR)
cfssl gencert \
-ca=ca.pem -ca-key=ca-key.pem \
-config=ca-config.json \
-profile=etcd \
etcd-csr.json | cfssljson -bare etcd
sudo mkdir -p /etc/etcd/pki
sudo cp ca.pem etcd.pem etcd-key.pem /etc/etcd/pki/
sudo chown -R etcd:etcd /etc/etcd/pki
sudo chmod 600 /etc/etcd/pki/*-key.pem
Mise en Place d’un Cluster etcd à Trois Nœuds
Un cluster etcd en production nécessite trois ou cinq membres. Avec trois membres, il tolère une panne tout en maintenant le quorum. Avec cinq, il tolère deux pannes simultanées.
Supposons trois nœuds avec les IPs suivantes :
etcd-1: 10.0.0.11etcd-2: 10.0.0.12etcd-3: 10.0.0.13
Créez /etc/etcd/etcd.conf.yml sur chaque nœud, en substituant les valeurs spécifiques au nœud :
# /etc/etcd/etcd.conf.yml — exemple pour etcd-1
name: etcd-1
data-dir: /var/lib/etcd
listen-peer-urls: https://10.0.0.11:2380
listen-client-urls: https://10.0.0.11:2379,https://127.0.0.1:2379
advertise-client-urls: https://10.0.0.11:2379
initial-advertise-peer-urls: https://10.0.0.11:2380
initial-cluster: >-
etcd-1=https://10.0.0.11:2380,
etcd-2=https://10.0.0.12:2380,
etcd-3=https://10.0.0.13:2380
initial-cluster-token: etcd-cluster-prod-01
initial-cluster-state: new
client-transport-security:
cert-file: /etc/etcd/pki/etcd.pem
key-file: /etc/etcd/pki/etcd-key.pem
trusted-ca-file: /etc/etcd/pki/ca.pem
client-cert-auth: true
peer-transport-security:
cert-file: /etc/etcd/pki/etcd.pem
key-file: /etc/etcd/pki/etcd-key.pem
trusted-ca-file: /etc/etcd/pki/ca.pem
peer-client-cert-auth: true
Créez l’unité systemd /etc/systemd/system/etcd.service sur tous les nœuds :
[Unit]
Description=etcd distributed key-value store
Documentation=https://etcd.io
After=network.target
[Service]
User=etcd
Group=etcd
Type=notify
ExecStart=/usr/local/bin/etcd --config-file /etc/etcd/etcd.conf.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Démarrez le cluster — les trois nœuds doivent démarrer dans le délai d’élection (par défaut 1 seconde) pour que l’amorçage initial réussisse :
# Exécutez sur les trois nœuds en succession rapide
sudo systemctl daemon-reload
sudo systemctl enable --now etcd
Vérifiez que le cluster s’est formé correctement :
export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379
export ETCDCTL_CACERT=/etc/etcd/pki/ca.pem
export ETCDCTL_CERT=/etc/etcd/pki/etcd.pem
export ETCDCTL_KEY=/etc/etcd/pki/etcd-key.pem
etcdctl endpoint health
etcdctl endpoint status --write-out=table
etcdctl member list --write-out=table
Sauvegarde etcd et Restauration de Snapshot
La sauvegarde etcd est indispensable en production. Un snapshot capture l’intégralité du magasin clés-valeurs à un instant donné. Sauvegardez toujours avant de mettre à jour etcd ou Kubernetes.
Créer un Snapshot
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d-%H%M%S).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/pki/ca.pem \
--cert=/etc/etcd/pki/etcd.pem \
--key=/etc/etcd/pki/etcd-key.pem
# Vérifier le snapshot
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot-*.db --write-out=table
Automatisez cela avec une tâche cron qui effectue la rotation des anciens snapshots :
# /etc/cron.d/etcd-backup
0 2 * * * etcd /usr/local/bin/etcdctl snapshot save \
/backup/etcd-$(date +\%Y\%m\%d).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/pki/ca.pem \
--cert=/etc/etcd/pki/etcd.pem \
--key=/etc/etcd/pki/etcd-key.pem && \
find /backup/ -name "etcd-*.db" -mtime +7 -delete
Restauration depuis un Snapshot
La restauration remplace le répertoire de données. Effectuez cette opération sur chaque membre du cluster :
# 1. Arrêtez etcd sur TOUS les nœuds d'abord
sudo systemctl stop etcd
# 2. Restaurez sur chaque nœud (utilisez --name et --initial-advertise-peer-urls uniques par nœud)
ETCDCTL_API=3 etcdutl snapshot restore /backup/etcd-snapshot.db \
--name etcd-1 \
--initial-cluster "etcd-1=https://10.0.0.11:2380,etcd-2=https://10.0.0.12:2380,etcd-3=https://10.0.0.13:2380" \
--initial-cluster-token etcd-cluster-prod-01 \
--initial-advertise-peer-urls https://10.0.0.11:2380 \
--data-dir /var/lib/etcd-restored
# 3. Permutez le répertoire de données
sudo mv /var/lib/etcd /var/lib/etcd-old
sudo mv /var/lib/etcd-restored /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd
# 4. Démarrez etcd sur TOUS les nœuds
sudo systemctl start etcd
Scénario Réel : Récupération d’un Plan de Contrôle Kubernetes
Vous disposez d’un cluster Kubernetes à trois nœuds où un nœud du plan de contrôle a perdu son disque. Le membre etcd sur ce nœud est disparu, et kubectl get nodes se bloque désormais car le serveur API ne peut pas atteindre le quorum pour les écritures.
Voici la procédure de récupération :
- Vérifiez l’appartenance actuelle depuis un nœud sain :
etcdctl member list. Vous verrez le membre défaillant avec une URL vide. - Supprimez le membre mort :
etcdctl member remove <MEMBER_ID> - Provisionnez un nouveau nœud avec le même nom d’hôte et la même IP (ou mettez à jour le DNS).
- Ajoutez le remplaçant :
etcdctl member add etcd-1-new --peer-urls=https://10.0.0.11:2380 - Démarrez etcd sur le nouveau nœud avec
ETCD_INITIAL_CLUSTER_STATE=existingdans la config — n’utilisez pasnew. - Observez la synchronisation du nouveau membre :
etcdctl endpoint statusaffichera le numéro de révision se rattraper en temps réel.
L’ensemble du processus prend généralement cinq à dix minutes pour un cluster avec moins de 1 Go de données etcd. Pendant la suppression et avant que le nouveau membre atteigne le quorum, Kubernetes continue de servir les lectures mais bloque les écritures.
Pièges et Cas Particuliers
Ne faites jamais tourner un nombre pair de membres etcd. Un cluster à deux membres n’a aucune tolérance aux pannes — la perte d’un membre entraîne immédiatement la perte du quorum. Un cluster à quatre membres ne tolère qu’une seule panne, comme trois membres, mais nécessite un nœud supplémentaire. Restez à 3 ou 5.
Les E/S disque sont le principal goulot d’étranglement d’etcd. etcd appelle fdatasync à chaque écriture. Si la latence de votre disque dépasse régulièrement 10 ms, vous verrez des élections de leader et des erreurs request timeout dans Kubernetes. Utilisez des SSD ou du stockage NVMe. Vérifiez la latence disque avec : fio --rw=write --ioengine=sync --fdatasync=1 --directory=/var/lib/etcd --size=22m --bs=2300 --name=etcd-bench.
etcd n’est pas une base de données généraliste. Le quota de stockage par défaut est de 2 Go. Les clusters Kubernetes avec de nombreux objets ou une utilisation intensive de ressources personnalisées peuvent atteindre cette limite. Surveillez etcd_mvcc_db_total_size_in_bytes dans Prometheus et compactez/défragmentez régulièrement :
# Compactez les anciennes révisions (gardez les 1000 dernières)
rev=$(etcdctl endpoint status --write-out=json | jq '.[0].Status.header.revision')
etcdctl compact $((rev - 1000))
etcdctl defrag --cluster
La dérive d’horloge provoque des élections de leader. etcd utilise l’horloge murale pour l’expiration des baux. Si les nœuds divergent de plus de quelques centaines de millisecondes, vous verrez des élections de leader intempestives. Exécutez NTP (chrony ou systemd-timesyncd) sur tous les nœuds etcd et vérifiez avec chronyc tracking.
La restauration de snapshot efface l’appartenance au cluster. Après une restauration, tous les membres sont traités comme un tout nouveau cluster avec l’appartenance encodée dans le snapshot. Ne restaurez jamais un snapshot sur un cluster en cours d’exécution sans arrêter tous les membres d’abord — vous créeriez une situation de cerveau divisé (split-brain).
Résolution de Problèmes
etcdserver: request timed out — Généralement une latence disque élevée. Vérifiez iostat -x 1 sur les nœuds etcd. Vérifiez également la connectivité entre pairs : etcdctl endpoint health depuis chaque nœud individuellement.
etcdserver: mvcc: database space exceeded — Le quota de stockage de 2 Go a été atteint. Exécutez la compaction et la défragmentation comme indiqué ci-dessus, ou augmentez le quota avec --quota-backend-bytes=4294967296 (4 Go) dans la config etcd.
raft: failed to send message — Pare-feu bloquant le port 2380 entre les pairs, ou un problème de CN du certificat pair. Vérifiez avec openssl s_client -connect 10.0.0.12:2380 depuis un autre nœud etcd.
certificate has expired — Les certificats pair et client etcd doivent être renouvelés avant leur expiration. Les clusters Kubernetes gérés avec kubeadm les renouvellent automatiquement entre 90 jours et 1 an, mais les clusters gérés manuellement ne le font pas. Vérifiez l’expiration : openssl x509 -in /etc/etcd/pki/etcd.pem -noout -dates.
etcd utilise trop de mémoire — etcd met en cache l’ensemble de travail en mémoire. Sur les clusters avec de nombreux objets, le RSS peut dépasser 8 Go. C’est normal. Définissez --snapshot-count=5000 (par défaut 100000) pour déclencher des snapshots plus fréquents et réduire la taille du log raft en mémoire.
Résumé
- etcd stocke tout l’état du cluster Kubernetes ; c’est le service le plus critique du plan de contrôle
- Déployez toujours trois ou cinq membres pour la production — uniquement des nombres impairs
- Activez le TLS mutuel sur les ports client et pair ; n’exposez jamais etcd sans authentification
- Prenez des snapshots quotidiens avec
etcdctl snapshot saveet vérifiez-les avecsnapshot status - Restaurez en arrêtant tous les membres, en exécutant
etcdutl snapshot restoresur chacun avec des paramètres de nœud uniques, en permutant le répertoire de données, puis en redémarrant - Surveillez la latence disque (restez sous 10 ms), la taille de la base de données (compactez en approchant 2 Go) et la stabilité du leader
- Utilisez
etcdctl member remove+member addpour remplacer un nœud défaillant sans restauration complète