TL;DR — Résumé Rapide

Sauvegarde et restauration etcd pour Kubernetes : snapshots, vérification, restauration multi-nœud, certificats kubeadm et surveillance en production.

etcd est le cœur de tout cluster Kubernetes : un magasin clé-valeur distribué et fortement cohérent qui conserve l’état complet — désiré et observé — de votre cluster. Lorsqu’etcd fonctionne correctement, les commandes kubectl répondent en millisecondes et les contrôleurs réconcillient en continu. Lorsqu’etcd est perdu sans sauvegarde, votre cluster disparaît — chaque définition de Deployment, chaque Secret, chaque politique RBAC, chaque CRD et chaque ConfigMap s’évaporent. Ce guide couvre tout ce dont vous avez besoin pour construire une stratégie de sauvegarde et de restauration etcd de niveau production.

Prérequis

  • Un cluster Kubernetes géré avec kubeadm (v1.22+) ou accès aux certificats etcd
  • etcdctl installé sur le nœud du plan de contrôle (la version doit correspondre à celle d’etcd)
  • Accès root ou sudo sur le nœud du plan de contrôle
  • kubectl configuré avec des permissions cluster-admin
  • Familiarité de base avec les composants du plan de contrôle Kubernetes
  • Pour les sauvegardes automatisées : accès à S3, GCS ou un stockage externe équivalent

Le Rôle d’etcd dans Kubernetes

Chaque fois que vous exécutez kubectl apply, le serveur API Kubernetes valide la requête et écrit l’objet résultant dans etcd. Tous les contrôleurs observent etcd via le mécanisme de watch du serveur API et réconcillient le cluster en conséquence. etcd est le seul composant avec état dans le plan de contrôle — tous les autres composants sont sans état et peuvent être redémarrés depuis zéro tant qu’etcd est intact.

Ce qui réside dans etcd :

  • Toutes les définitions d’objets API : Pods, Deployments, StatefulSets, DaemonSets, Services, Ingresses
  • Secrets et ConfigMaps
  • RBAC : Roles, ClusterRoles, RoleBindings, ClusterRoleBindings
  • Custom Resource Definitions et toutes les instances de ressources personnalisées
  • Définitions de Namespaces, ResourceQuotas, LimitRanges
  • ServiceAccounts et tokens associés
  • Enregistrements de nœuds et objets de lease
  • Enregistrements d’élection de leader pour kube-controller-manager et kube-scheduler

Ce qui ne réside pas dans etcd : les données réelles stockées dans les PersistentVolumes. etcd ne stocke que les objets PVC et PV (métadonnées et liaison), pas les octets sur disque.

Architecture etcd : Raft, WAL et Snapshots

etcd utilise l’algorithme de consensus Raft pour répliquer l’état sur un cluster de membres en nombre impair (typiquement 3 ou 5). Raft élit un leader qui traite toutes les écritures ; les suiveurs répliquent le journal du leader. Le cluster tolère (n-1)/2 défaillances de membres — un cluster à 3 nœuds survit à 1 défaillance, un à 5 nœuds survit à 2.

Les écritures sont d’abord ajoutées au Write-Ahead Log (WAL) sur disque, puis appliquées à un B-tree en mémoire (bbolt). Périodiquement, etcd prend un snapshot interne du B-tree sur disque et tronque le WAL pour éviter une croissance illimitée.

La commande etcdctl snapshot save déclenche un snapshot de l’état actuel du B-tree. Ce snapshot est une sauvegarde complète et autonome de toutes les données etcd au moment où il a été pris.

Méthodes de Sauvegarde

Méthode 1 : etcdctl snapshot save (Recommandée)

La méthode canonique de sauvegarde. Sur un cluster kubeadm, etcd tourne comme pod statique avec TLS. Les certificats se trouvent dans /etc/kubernetes/pki/etcd/.

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Méthode 2 : CronJob Automatisé

Déployez un CronJob Kubernetes sur le plan de contrôle qui monte les certificats etcd de l’hôte et écrit les snapshots dans un PVC ou un stockage cloud :

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-backup
  namespace: kube-system
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          containers:
          - name: etcd-backup
            image: bitnami/etcd:3.5
            command:
            - /bin/sh
            - -c
            - |
              ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \
                --endpoints=https://127.0.0.1:2379 \
                --cacert=/etc/kubernetes/pki/etcd/ca.crt \
                --cert=/etc/kubernetes/pki/etcd/server.crt \
                --key=/etc/kubernetes/pki/etcd/server.key
            volumeMounts:
            - name: etcd-certs
              mountPath: /etc/kubernetes/pki/etcd
              readOnly: true
            - name: backup-dir
              mountPath: /backup
          volumes:
          - name: etcd-certs
            hostPath:
              path: /etc/kubernetes/pki/etcd
          - name: backup-dir
            persistentVolumeClaim:
              claimName: etcd-backup-pvc
          restartPolicy: OnFailure
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
          - key: node-role.kubernetes.io/control-plane
            effect: NoSchedule

Comparatif des Outils de Sauvegarde

OutilÉtat etcdDonnées PVGranularité de RestaurationComplexité
etcdctl snapshotOuiNonCluster completFaible
Velero + plugin etcdOuiOuiNamespace ou completMoyenne
etcd-backup-operatorOuiNonCluster completMoyenne
kube-backupOuiNonCluster completFaible
CronJob manuelOuiNonCluster completFaible

Vérification du Snapshot

Ne faites jamais confiance à une sauvegarde que vous n’avez pas vérifiée. Après chaque snapshot :

ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db \
  --write-out=table

Si TOTAL KEYS est 0 ou si le hash est malformé, le snapshot est corrompu. Intégrez la vérification dans votre CronJob de sauvegarde et configurez des alertes en cas d’échec.

Procédures de Restauration

Cluster kubeadm à Nœud Unique

Étape 1 : Arrêter le serveur API et etcd

mkdir -p /tmp/k8s-manifests-backup
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/k8s-manifests-backup/
mv /etc/kubernetes/manifests/etcd.yaml /tmp/k8s-manifests-backup/
sleep 10
ps aux | grep etcd

Étape 2 : Sauvegarder le répertoire de données existant

mv /var/lib/etcd /var/lib/etcd.bak

Étape 3 : Restaurer le snapshot

ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --data-dir=/var/lib/etcd \
  --initial-cluster=default=https://127.0.0.1:2380 \
  --initial-cluster-token=etcd-cluster-1 \
  --initial-advertise-peer-urls=https://127.0.0.1:2380

Étape 4 : Restaurer les manifests et vérifier

mv /tmp/k8s-manifests-backup/etcd.yaml /etc/kubernetes/manifests/
mv /tmp/k8s-manifests-backup/kube-apiserver.yaml /etc/kubernetes/manifests/
sleep 30
kubectl get nodes

Cluster kubeadm Multi-Nœuds

Pour un cluster à 3 nœuds du plan de contrôle (HA), vous devez restaurer sur tous les membres etcd simultanément avec des valeurs cohérentes pour --initial-cluster et --initial-cluster-token :

# Sur chaque nœud du plan de contrôle, exécutez la restauration avec le MÊME snapshot et token
# mais avec le --name et --initial-advertise-peer-urls corrects pour ce nœud

# Nœud 1
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --name=etcd-cp1 \
  --data-dir=/var/lib/etcd \
  --initial-cluster=etcd-cp1=https://10.0.0.1:2380,etcd-cp2=https://10.0.0.2:2380,etcd-cp3=https://10.0.0.3:2380 \
  --initial-cluster-token=etcd-restore-token-$(date +%s) \
  --initial-advertise-peer-urls=https://10.0.0.1:2380

Utilisez un --initial-cluster-token unique et différent de l’original pour éviter que le cluster restauré ne rejoigne accidentellement l’ancien cluster dégradé.

Considérations pour Kubernetes Managé

EKS, GKE, AKS — Le fournisseur cloud gère etcd en interne. Vous ne pouvez pas accéder directement à etcd. Utilisez les mécanismes natifs du fournisseur :

  • EKS: Velero avec S3 ; AWS n’expose pas etcd directement
  • GKE: Velero ; Google gère etcd avec des sauvegardes automatiques sur Autopilot
  • AKS: Velero + Azure Blob ; Microsoft gère etcd pour les node pools managés

Surveillance de la Santé d’etcd

# Vérifier la santé du point de terminaison
ETCDCTL_API=3 etcdctl endpoint health \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

# Vérifier le leader et l'état des membres
ETCDCTL_API=3 etcdctl endpoint status --write-out=table \
  --endpoints=https://10.0.0.1:2379,https://10.0.0.2:2379,https://10.0.0.3:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Alertes Prometheus recommandées pour etcd :

  • etcd_server_has_leader == 0 — aucun leader élu (critique)
  • etcd_disk_wal_fsync_duration_seconds{quantile="0.99"} > 0.01 — écritures WAL lentes
  • etcd_server_proposals_failed_total > 0 — échecs de consensus
  • etcd_mvcc_db_total_size_in_bytes > 8589934592 — BD approchant la limite de 8 Go

Compaction et Défragmentation

etcd conserve un historique de toutes les révisions de clés. Avec le temps, cela consomme un espace disque significatif. Activez la compaction automatique :

--auto-compaction-mode=periodic
--auto-compaction-retention=1h

Exécutez la défragmentation périodiquement pendant les heures creuses :

ETCDCTL_API=3 etcdctl defrag \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Réglage des Performances

etcd est extrêmement sensible à la latence disque. Recommandations :

  • SSD dédié: Ne partagez jamais le disque de données etcd avec des charges de travail applicatives. Utilisez un NVMe ou SSD avec des IOPS d’écriture aléatoire soutenue > 2000.
  • Timeouts de heartbeat et d’élection: Le heartbeat-interval par défaut est 100ms et le election-timeout est 1000ms. Dans des environnements à latence élevée, augmentez à 250ms / 1250ms.
  • Quota de BD: La valeur par défaut est 2 Go. Augmentez à 8 Go pour les grands clusters : --quota-backend-bytes=8589934592

Script de Sauvegarde de Production avec Alertes

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/etcd-backups"
RETENTION_COUNT=24
S3_BUCKET="s3://mon-cluster-etcd-backups"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
ETCD_ENDPOINTS="https://127.0.0.1:2379"
CACERT="/etc/kubernetes/pki/etcd/ca.crt"
CERT="/etc/kubernetes/pki/etcd/server.crt"
KEY="/etc/kubernetes/pki/etcd/server.key"

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
SNAPSHOT_FILE="${BACKUP_DIR}/etcd-${TIMESTAMP}.db"

alerte() {
  local msg="$1"
  curl -s -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"[etcd-backup] ${msg}\"}" "${SLACK_WEBHOOK}" || true
}

mkdir -p "${BACKUP_DIR}"

if ! ETCDCTL_API=3 etcdctl snapshot save "${SNAPSHOT_FILE}" \
    --endpoints="${ETCD_ENDPOINTS}" \
    --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}"; then
  alerte "CRITIQUE : etcd snapshot save a ÉCHOUÉ sur $(hostname) à ${TIMESTAMP}"
  exit 1
fi

KEYS=$(ETCDCTL_API=3 etcdctl snapshot status "${SNAPSHOT_FILE}" \
  --write-out=json | python3 -c "import sys,json; print(json.load(sys.stdin)['totalKey'])")
if [ "${KEYS}" -lt 100 ]; then
  alerte "AVERTISSEMENT : le snapshot n'a que ${KEYS} clés — snapshot vide ou corrompu possible"
  exit 1
fi

aws s3 cp "${SNAPSHOT_FILE}" "${S3_BUCKET}/$(basename ${SNAPSHOT_FILE})" \
  --storage-class STANDARD_IA

ls -t "${BACKUP_DIR}"/etcd-*.db | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm -f

echo "Sauvegarde terminée : ${SNAPSHOT_FILE} (${KEYS} clés)"

Scénarios de Reprise après Sinistre

Scénario 1 : Défaillance d’un membre (quorum intact) — Le cluster continue de fonctionner. Remplacez le membre défaillant avec etcdctl member remove + etcdctl member add sans restauration.

Scénario 2 : Perte de quorum (majorité des membres hors ligne) — Le cluster devient en lecture seule. Si les données sont intactes, rétablissez la connectivité. Si les données sont perdues, restaurez depuis un snapshot sur tous les membres.

Scénario 3 : Restauration complète du cluster — Arrêtez tous les composants du plan de contrôle, restaurez le snapshot sur chaque nœud avec un --initial-cluster-token cohérent, redémarrez dans l’ordre : etcd d’abord, puis kube-apiserver, puis kube-controller-manager et kube-scheduler.

Pièges et Cas Particuliers

Incompatibilité de version etcdctl — Définissez toujours ETCDCTL_API=3. Vérifiez que la version du client correspond à celle du serveur. Les incompatibilités causent des échecs silencieux ou des restaurations corrompues.

La restauration écrase le répertoire de donnéesetcdctl snapshot restore écrit dans --data-dir. Si le répertoire existe déjà, la restauration échoue. Déplacez toujours le répertoire existant au préalable.

Décalage d’horloge entre membres — Les certificats TLS des pairs etcd sont sensibles au temps. Assurez-vous que NTP est configuré et synchronisé sur tous les nœuds du plan de contrôle.

Résumé

  • etcd stocke tout l’état du cluster Kubernetes ; le perdre sans sauvegarde signifie reconstruire de zéro
  • Utilisez etcdctl snapshot save avec les flags TLS pointant vers /etc/kubernetes/pki/etcd/ pour les clusters kubeadm
  • Exécutez toujours etcdctl snapshot status pour vérifier les snapshots après leur création
  • La restauration nécessite d’arrêter le serveur API et etcd, d’exécuter etcdctl snapshot restore et de redémarrer le plan de contrôle
  • La restauration multi-nœuds nécessite un --initial-cluster-token cohérent et des --initial-advertise-peer-urls corrects par nœud
  • Activez la compaction automatique et exécutez etcdctl defrag mensuellement
  • Dédiez un SSD à faible latence aux données etcd ; surveillez la latence WAL fsync avec Prometheus
  • Stockez les snapshots hors site (S3/GCS) avec au moins 24h de rétention ; automatisez avec un CronJob + script d’alertes

Articles Connexes