深色模式
etcd 备份与恢复
摘要:etcd 里存着集群的全部状态,丢了它集群就等于重建。本文演示用 etcdctl 打快照、校验、恢复到新集群的完整过程,并给出定时备份与健康检查的实践方式。
适用环境
- kubeadm 搭建的自管集群(托管集群无需也不能自行备份 etcd)
- 控制面节点可登录,有
etcdctl(或用 etcd 容器内的二进制) - 备份存储位置独立于集群节点
操作步骤
一、确认 etcd 访问参数
bash
kubectl -n kube-system get pod -l component=etcd
ps aux | grep etcd | grep -- --endpoints # 或看静态 Pod 配置
sudo grep -E "listen-client-urls|cert-file|key-file|trusted-ca-file" /etc/kubernetes/manifests/etcd.yaml1
2
3
2
3
典型参数:--listen-client-urls=https://127.0.0.1:2379,证书在 /etc/kubernetes/pki/etcd/。
二、打一次快照
bash
sudo ETCDCTL_API=3 etcdctl snapshot save /data/etcd-snap-$(date +%F-%H%M).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.key1
2
3
4
5
2
3
4
5
若节点上没有 etcdctl,直接用容器:
bash
sudo docker run --rm -v /data:/backup \
-v /etc/kubernetes/pki/etcd:/etc/kubernetes/pki/etcd \
--network host registry.k8s.io/etcd:3.5.12-0 \
sh -c 'ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snap.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'1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
三、校验快照有效性
bash
sudo ETCDCTL_API=3 etcdctl snapshot status /data/etcd-snap-2026-10-09.db -w table1
输出应包含 revision、总键数、数据大小。只有 status 能正常读出的快照才是可恢复的。
注意
备份必须立刻校验。很多团队备份跑了一年,真要恢复时才发现快照一直是空的或已损坏。
四、配置定时备份
bash
sudo mkdir -p /opt/scripts /data/etcd-backup
sudo tee /opt/scripts/etcd-backup.sh <<'EOF'
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/data/etcd-backup
KEEP_DAYS=7
SNAP="$BACKUP_DIR/etcd-$(date +%F-%H%M%S).db"
ETCDCTL_API=3 etcdctl snapshot save "$SNAP" \
--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
ETCDCTL_API=3 etcdctl snapshot status "$SNAP" -w table
find "$BACKUP_DIR" -name 'etcd-*.db' -mtime +${KEEP_DAYS} -delete
EOF
sudo chmod +x /opt/scripts/etcd-backup.sh1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
加入 crontab(每天凌晨 2 点):
bash
echo "0 2 * * * /opt/scripts/etcd-backup.sh >> /var/log/etcd-backup.log 2>&1" | sudo crontab -1
五、健康检查
bash
sudo ETCDCTL_API=3 etcdctl endpoint health --write-out=table \
--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
sudo ETCDCTL_API=3 etcdctl endpoint status --write-out=table \
--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.key1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
关注 DB SIZE(接近 2GB 配额会拒绝写入)和 RAFT TERM 是否一致(不一致说明有节点掉队)。
六、灾难恢复(单控制面示例)
bash
# 1. 停止控制面组件(静态 Pod 会被 kubelet 重建,先移走清单)
sudo mkdir -p /etc/kubernetes/manifests.bak
sudo mv /etc/kubernetes/manifests/*.yaml /etc/kubernetes/manifests.bak/
# 2. 恢复数据到新目录
sudo ETCDCTL_API=3 etcdctl snapshot restore /data/etcd-snap-2026-10-09.db \
--data-dir=/var/lib/etcd-restore \
--name=<节点名> \
--initial-cluster=<节点名>=https://<节点IP>:2380 \
--initial-advertise-peer-urls=https://<节点IP>:2380
# 3. 用新数据目录启动 etcd
sudo rm -rf /var/lib/etcd
sudo mv /var/lib/etcd-restore /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd 2>/dev/null || true
# 4. 还原静态 Pod 清单,让控制面重新起来
sudo mv /etc/kubernetes/manifests.bak/*.yaml /etc/kubernetes/manifests/1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
危险
恢复操作会丢弃从快照时间点之后的所有集群变更。多控制面集群必须同时在所有 etcd 成员上恢复,且用同一份快照,否则会出现数据分裂。操作前先停控制面,切勿在线替换数据目录。
七、恢复后验证
bash
kubectl get nodes
kubectl get pod -A
kubectl get --raw /healthz1
2
3
2
3
验证
- [ ]
etcdctl snapshot status能读出快照元信息 - [ ] 定时脚本生成的日志文件有成功记录
- [ ]
etcdctl endpoint health显示 healthy - [ ] 在测试集群完整演练过一次恢复流程
常见坑
snapshot save报context deadline exceeded:证书路径或 endpoints 写错,也可能是 etcd 负载过高,重试并延长超时。- 备份放在同一台机器上:节点磁盘损坏时备份一起没,必须异地保存。
- 快照从未校验:恢复时才发现损坏,见上文警告。
- 忘记
--data-dir指定新目录:直接覆盖原目录会破坏正在运行的 etcd。 - 只恢复了一个 etcd 成员:多成员集群会出现 quorum 不一致,集群仍不可用。