Kubernetes etcd Snapshot Backup and Recovery Procedure

etcd serves as the cirtical distributed key-value store for Kubernetes, holding cluster state and configuration data. Regular backups are essential for disaster recovery and cluster migration. This guide outlines a complete procedure for backing up and restoring an etcd cluster using etcdctl, assuming a three-node HA setup deployed via kubeadm.

Prerequisites

  • Kubernetes version: 1.23.17
  • Three master nodes: master01 (192.168.1.161), master02 (192.168.1.162), master03 (192.168.1.163)
  • Access to TLS certificates under /etc/kubernetes/pki/etcd/

Install etcdctl

Download and install etcdctl on one master node:

wget https://gh.monlor.com/https://github.com/etcd-io/etcd/releases/download/v3.4.30/etcd-v3.4.30-linux-amd64.tar.gz
tar -zxf etcd-v3.4.30-linux-amd64.tar.gz
mv etcd-v3.4.30-linux-amd64/etcdctl /usr/local/bin/
chmod +x /usr/local/bin/etcdctl

Copy the binary to other master nodes:

scp /usr/local/bin/etcdctl master02:/usr/local/bin/
scp /usr/local/bin/etcdctl master03:/usr/local/bin/

Configure Environment Variables

Add the following to ~/.bashrc on all nodes:

export ETCDCTL_API=3
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key
export ETCDCTL_ENDPOINTS=192.168.1.161:2379,192.168.1.162:2379,192.168.1.163:2379

Reload the shell configuration:

source ~/.bashrc

Verify Cluster Health

Check endpoint status using a specific endpoint:

ETCDCTL_API=3 \
ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt \
ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt \
ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key \
ETCDCTL_ENDPOINTS=192.168.1.161:2379 \
etcdctl endpoint health --write-out=table

Expected output:

ENDPOINT HEALTH TOOK ERROR
192.168.1.161:2379 true 18.2ms
192.168.1.162:2379 true 15.7ms
192.168.1.163:2379 true 16.1ms

Perform Backup

Create a dedicated backup directory on all nodes:

mkdir -p /opt/etcd_backup

Execute snapshot on a single endpoint (e.g., master01):

ETCDCTL_API=3 \
ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt \
ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt \
ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key \
ETCDCTL_ENDPOINTS=192.168.1.161:2379 \
etcdctl snapshot save /opt/etcd_backup/snap-etcd-$(date +%F-%H-%M-%S).db

Confirm the snapshot file exists:

ls -l /opt/etcd_backup/snap-etcd-*.db

Prepare for Recovery

Delete test resources to simulate data loss:

kubectl delete deployment nginx
kubectl -n ops delete deployment redis-single

Stop etcd on all master nodes by moving the manifest out of the manifests directory:

mv /etc/kubernetes/manifests/etcd.yaml /home/

Backup existing etcd data:

mv /var/lib/etcd /var/lib/etcd-$(date +%F-%H-%M-%S)-backup

Restore Snapshot on Each Node

Transfer the snapshot file to all masters:

scp /opt/etcd_backup/snap-etcd-*.db master02:/opt/etcd_backup/
scp /opt/etcd_backup/snap-etcd-*.db master03:/opt/etcd_backup/

On master01:

ETCDCTL_API=3 etcdctl snapshot restore /opt/etcd_backup/snap-etcd-2024-09-06-11-12-02.db \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  --data-dir=/var/lib/etcd \
  --endpoints=https://127.0.0.1:2379 \
  --initial-cluster=master01=https://192.168.1.161:2380,master02=https://192.168.1.162:2380,master03=https://192.168.1.163:2380 \
  --name=master01 \
  --initial-advertise-peer-urls=https://192.168.1.161:2380

On master02:

ETCDCTL_API=3 etcdctl snapshot restore /opt/etcd_backup/snap-etcd-2024-09-06-11-12-02.db \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  --data-dir=/var/lib/etcd \
  --endpoints=https://127.0.0.1:2379 \
  --initial-cluster=master01=https://192.168.1.161:2380,master02=https://192.168.1.162:2380,master03=https://192.168.1.163:2380 \
  --name=master02 \
  --initial-advertise-peer-urls=https://192.168.1.162:2380

On master03:

ETCDCTL_API=3 etcdctl snapshot restore /opt/etcd_backup/snap-etcd-2024-09-06-11-12-02.db \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  --data-dir=/var/lib/etcd \
  --endpoints=https://127.0.0.1:2379 \
  --initial-cluster=master01=https://192.168.1.161:2380,master02=https://192.168.1.162:2380,master03=https://192.168.1.163:2380 \
  --name=master03 \
  --initial-advertise-peer-urls=https://192.168.1.163:2380

Restart etcd

Restore the etcd manifest on all nodes:

mv /home/etcd.yaml /etc/kubernetes/manifests/

The kubelet will automatically restart etcd pods. Wait 30–60 seconds for the cluster to stabilize.

Validation

Confirm restored resources:

kubectl get deployments -A | grep -E "(nginx|redis-single)"

Verify etcd cluster health:

ETCDCTL_API=3 etcdctl endpoint status --write-out=table

Automate Backup with Script

Create a backup script at /scripts/etcd_backup.sh:

#!/bin/bash

export ETCDCTL_API=3
BACKUP_DIR="/opt/etcd_backup"
SNAPSHOT_FILE="snap-etcd-$(date +%F-%H-%M-%S).db"
SNAPSHOT_PATH="$BACKUP_DIR/$SNAPSHOT_FILE"

mkdir -p "$BACKUP_DIR"

ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt \
ETCDCTL_CERT=/etc/kubernetes/pki/etcd/peer.crt \
ETCDCTL_KEY=/etc/kubernetes/pki/etcd/peer.key \
ETCDCTL_ENDPOINTS=192.168.1.161:2379 \
etcdctl snapshot save "$SNAPSHOT_PATH"

if [ $? -eq 0 ]; then
  echo "✅ Backup successful: $SNAPSHOT_PATH"
else
  echo "❌ Backup failed"
  exit 1
fi

Make executable and schedule weekly via cron:

chmod +x /scripts/etcd_backup.sh
crontab -e
# Add line: 0 0 * * 3 /scripts/etcd_backup.sh

Tags: etcd etcdctl kubernetes Backup recovery

Posted on Fri, 30 Oct 2026 16:47:20 +0000 by DjMikeS