起因
K8s 整个 cluster 状态存在 etcd:
- 所有 deployment / service / configmap / secret
- node 状态
- 所有 namespace
etcd 挂 → cluster 整体瘫。
更恐怖:etcd 数据损坏(disk 错 / 误操作)→ 数据丢失。
定期 etcd backup + 演练 restore 是 cluster 运维基础功。
没做过 restore 演练等于没 backup。
看 etcd 状态
# kubeadm 部署的 cluster
sudo etcdctl --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 \
endpoint status --write-out=table
+------------------------+------------+---------+---------+--------+
| ENDPOINT | DB SIZE | LEADER | RAFT IDX| ALARMS |
+------------------------+------------+---------+---------+--------+
| 10.0.1.10:2379 | 250 MB | true | 123456 | |
| 10.0.1.11:2379 | 250 MB | false | 123456 | |
| 10.0.1.12:2379 | 250 MB | false | 123456 | |
+------------------------+------------+---------+---------+--------+
3 个 endpoint 应一致 + 1 个 leader + 无 alarms。
创建 snapshot
sudo ETCDCTL_API=3 etcdctl \
--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 \
snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db
Snapshot saved at /backup/etcd-...db
snapshot 是单 binary 文件,几百 MB 量级(小 cluster)。
自动化备份 (cronjob)
# /etc/cron.d/etcd-backup
0 */6 * * * root /usr/local/bin/etcd-backup.sh
#!/bin/bash
# /usr/local/bin/etcd-backup.sh
set -euo pipefail
BACKUP_DIR=/backup
RETENTION_DAYS=7
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ETCDCTL_API=3 etcdctl \
--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 \
snapshot save "$BACKUP_DIR/etcd-$TIMESTAMP.db"
# 上传到 S3
aws s3 cp "$BACKUP_DIR/etcd-$TIMESTAMP.db" s3://my-backups/etcd/
# 删本地老备份
find $BACKUP_DIR -name 'etcd-*.db' -mtime +$RETENTION_DAYS -delete
# 删 S3 老备份(lifecycle policy 也行)
aws s3 ls s3://my-backups/etcd/ | awk '{print $4}' | while read f; do
days_old=$((($(date +%s) - $(date -d $(echo $f | sed 's/etcd-\(....\)\(..\)\(..\)-.*/\1-\2-\3/') +%s)) / 86400))
if [ $days_old -gt 30 ]; then
aws s3 rm s3://my-backups/etcd/$f
fi
done
每 6 小时备份 + 7 天本地 + 30 天 S3。
restore (灾难恢复)
演练步骤(请在测试环境跑过几次):
# 1. 停所有 etcd 节点的 etcd(kubeadm 用 static pod 控制)
sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/
# 等几秒确认 etcd 停了
sudo crictl ps | grep etcd
# 2. 备份当前 data dir
sudo mv /var/lib/etcd /var/lib/etcd.bak
# 3. restore snapshot
sudo ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-xxx.db \
--data-dir /var/lib/etcd \
--name etcd-node-1 \
--initial-cluster etcd-node-1=https://10.0.1.10:2380,etcd-node-2=https://10.0.1.11:2380,etcd-node-3=https://10.0.1.12:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls https://10.0.1.10:2380
# 4. 在每节点上做 3 / restore
# 5. 启动 etcd
sudo mv /tmp/etcd.yaml /etc/kubernetes/manifests/
# 6. 验证
kubectl get nodes
kubectl get pods -A
cluster 回到 snapshot 时点状态。
snapshot 之后创建的资源(pod / deployment 等)丢失(除非应用 IaC / GitOps
能重 apply)。
velero (更高层备份)
etcd snapshot 是 raw K8s API state。
Velero:备份 + restore K8s 资源 + PV 数据:
helm install velero vmware-tanzu/velero \
--namespace velero --create-namespace \
--set configuration.provider=aws \
--set configuration.backupStorageLocation.bucket=my-backups \
...
# 备份 namespace
velero backup create myapp-backup --include-namespaces myapp
# 备份全集群(除 system)
velero backup create cluster-backup --exclude-namespaces kube-system,kube-public
# 列出
velero backup get
# restore
velero restore create --from-backup myapp-backup --namespace-mappings myapp:myapp-restore
Velero 优势 vs etcd snapshot:
- 选择性备份(按 namespace / label)
- restore 到不同 namespace / cluster
- PV 数据快照(CSI snapshot 支持)
- 跨 cluster migration
etcd snapshot 是最后兜底(整 cluster 灾难);
Velero 是日常运维(误删 namespace / 迁移 / 测试 restore)。
两者都做。
测试 restore 至关重要
经验:没演练过的 backup = 没 backup。
每季度跑一次:
- spin up 临时 cluster
- 从 backup restore
- 验证应用能跑
- 文档化每步
第一次跑会发现:
- 漏备份某 resource
- restore script 步骤错
- 某 PV 数据没快照
修完 → real disaster 时不慌。
etcd 调优
defrag (DB 碎片整理):
etcdctl defrag --endpoints=...
DB size 大但 key 少 → 碎片多。定期 defrag。
每 leader change / 大批量改后跑。
quota:
etcd --quota-backend-bytes=8589934592 # 8 GB
默认 2 GB → 大 cluster 不够。
monitor:
etcd_mvcc_db_total_size_in_bytes
etcd_disk_wal_fsync_duration_seconds
etcd_server_leader_changes_seen_total
leader changes 频繁 → 网络 / disk 问题。
多 cluster: 跨 region backup
# velero schedule
velero schedule create daily-backup --schedule="0 2 * * *" --ttl 720h \
--include-namespaces myapp \
--storage-location aws-prod-east
# 跨 region replication(备份不放同 region 防 region-wide 灾)
aws s3 cp s3://my-backups-east/... s3://my-backups-west/...
与 cloud managed (EKS / GKE / AKS)
cloud managed K8s 的 etcd 是 cloud provider 维护。
- 自动备份 / failover
- 但你不能直接 etcdctl snapshot
仍要用 Velero 备份 resource 层(防 namespace 误删 / restore 到其它
cluster)。
真实 incident case
某客户误执行 kubectl delete namespace prod。
恢复:
- 看最近 velero backup(4 小时前)
velero restore create --from-backup ... --include-namespaces prod- 30 分钟后 deployment / service / configmap / secret 全回
- PV 数据完整(CSI snapshot)
无 backup → cluster 完蛋。有 backup + 演练 → 30 分钟恢复。
踩过的坑
-
backup 没测:以为有 backup → 真灾难时发现 backup file 损坏 /
不完整。定期 restore 测试。 -
etcd snapshot 不包括 secret in etcd-encryption-config 外:
K8s 1.13+ 支持 etcd 加密。restore 后 encryption config 不存在
→ 解密失败。备份时同时 cp encryption config。 -
velero 不备 PV 数据 by default:要装 CSI plugin 或者 restic
integration。 -
restore 后 IP 变:service 重新创建 ClusterIP 可能变 → DNS 改
传播延迟。 -
etcd full:DB size 超 quota → cluster read-only。
defrag+
alarm disarm。
登录后参与评论。