Lab 状态:实跑通过
快照恢复与 quorum 重建通过
安全边界:本 Lab 只允许在一次性虚拟机或本地 Docker 中进行。生产 etcd 恢复要停止全部控制平面 kubelet,影响整个集群 API;不要在生产上执行
snapshot restore、替换数据目录或--force-new-cluster。真实操作必须先备份证书、加密配置和旧数据目录,并由变更负责人确认快照时点和可丢失窗口。
准备 Docker。实验使用一个不映射宿主机端口的 etcd 容器,客户端命令都通过 docker exec 在容器内执行,避免误连其他 etcd。镜像标签沿用现有 etcd Lab 中已验证的镜像;如果本地没有该镜像,换成你确认过来源和版本的 etcd 镜像。
mkdir -p /tmp/lab-etcd-restore/backup
docker version --format '{{.ServerVersion}}'
timeout 30 docker volume create lab-etcd-data
timeout 120 docker run -d --name lab-etcd \
-v lab-etcd-data:/etcd-data \
-v /tmp/lab-etcd-restore/backup:/backup \
quay.io/coreos/etcd:v3.5.15 \
/usr/local/bin/etcd \
--name=lab \
--data-dir=/etcd-data \
--listen-client-urls=http://0.0.0.0:2379 \
--advertise-client-urls=http://127.0.0.1:2379 \
--listen-peer-urls=http://0.0.0.0:2380 \
--initial-advertise-peer-urls=http://127.0.0.1:2380 \
--initial-cluster=lab=http://127.0.0.1:2380 \
--initial-cluster-token=lab-etcd-token \
--initial-cluster-state=new
timeout 60 bash -c 'until docker exec lab-etcd etcdctl endpoint health; do sleep 2; done'
docker exec lab-etcd etcdctl endpoint status -w table
写入一组可识别的键,记录快照前的键值内容和 revision。不要只看“写入成功”,要把基线保存成文件,恢复后逐字对比:
timeout 30 docker exec lab-etcd etcdctl put /lab/before snapshot-time
timeout 30 docker exec lab-etcd etcdctl put /lab/config mode=baseline
docker exec lab-etcd etcdctl get /lab --prefix > /tmp/lab-etcd-restore/backup/before.txt
docker exec lab-etcd etcdctl get /lab --prefix --keys-only | grep -c .
docker exec lab-etcd etcdctl endpoint status -w table
保存快照并校验。快照文件通过 bind mount 出现在宿主机 /tmp/lab-etcd-restore/backup,再计算校验和;真实环境还要把快照复制到独立存储,不能只留在待恢复节点:
timeout 60 docker exec lab-etcd etcdctl snapshot save /backup/snapshot.db
docker exec lab-etcd etcdutl snapshot status /backup/snapshot.db -w table
sha256sum /tmp/lab-etcd-restore/backup/snapshot.db \
| tee /tmp/lab-etcd-restore/backup/snapshot.db.sha256
如果镜像内没有 etcdutl,不要跳过校验;使用与 etcd 版本匹配的 etcdutl 二进制在宿主机或另一容器中校验,并记录版本来源。etcdctl snapshot status 在部分版本中已不再推荐,优先使用 etcdutl。
快照完成后继续写入,并修改一个已存在的键,模拟快照时间点之后发生的业务变更。恢复后这些变更应当消失:
timeout 30 docker exec lab-etcd etcdctl put /lab/after will-be-lost
timeout 30 docker exec lab-etcd etcdctl put /lab/before mutated-after-snapshot
docker exec lab-etcd etcdctl get /lab --prefix > /tmp/lab-etcd-restore/backup/after-writes.txt
docker exec lab-etcd etcdctl get /lab/before
先停止 etcd 容器,确认客户端无法再写入,再准备恢复。旧容器和旧数据卷都保留,不执行 docker rm 或删除卷,它们是回滚材料:
timeout 60 docker stop lab-etcd
timeout 30 docker ps -a --filter name=lab-etcd --format '{{.Names}} {{.Status}}'
timeout 30 docker exec lab-etcd etcdctl put /lab/should-fail nope 2>/dev/null; echo "write_exit=$?"
创建一个全新的数据卷,把同一份快照恢复进去。不要覆盖旧卷,也不要把不同快照或不同集群的成员混在一起。单成员实验使用原成员名、原 token 和原 peer URL:
timeout 30 docker volume create lab-etcd-restored
timeout 120 docker run --rm \
-v lab-etcd-restored:/etcd-data \
-v /tmp/lab-etcd-restore/backup:/backup:ro \
--entrypoint /usr/local/bin/etcdutl \
quay.io/coreos/etcd:v3.5.15 \
snapshot restore /backup/snapshot.db \
--name=lab \
--data-dir=/etcd-data \
--initial-cluster=lab=http://127.0.0.1:2380 \
--initial-cluster-token=lab-etcd-token \
--initial-advertise-peer-urls=http://127.0.0.1:2380
用恢复后的数据卷启动新容器,避免与旧容器同名。启动参数要沿用原集群的成员名、token 和 peer URL;initial-cluster-state 的具体取值以当前 etcd 版本的官方恢复文档为准,不能把本页命令直接套到生产集群:
timeout 120 docker run -d --name lab-etcd-restored \
-v lab-etcd-restored:/etcd-data \
quay.io/coreos/etcd:v3.5.15 \
/usr/local/bin/etcd \
--name=lab \
--data-dir=/etcd-data \
--listen-client-urls=http://0.0.0.0:2379 \
--advertise-client-urls=http://127.0.0.1:2379 \
--listen-peer-urls=http://0.0.0.0:2380 \
--initial-advertise-peer-urls=http://127.0.0.1:2380 \
--initial-cluster=lab=http://127.0.0.1:2380 \
--initial-cluster-token=lab-etcd-token \
--initial-cluster-state=existing
timeout 60 bash -c 'until docker exec lab-etcd-restored etcdctl endpoint health; do sleep 2; done'
恢复后的成员应只有一个 leader,endpoint health 返回 healthy,alarm list 为空。读取 /lab 前缀时,/lab/before 应回到 snapshot-time,快照后的 mutated-after-snapshot 和 /lab/after 都不存在;这证明恢复回到了快照 revision,而不是把旧数据目录原样启动。
成功的判据是:成员健康且 leader 唯一;/lab 下的键值与快照前基线文件一致;快照后的写入消失;键数量与快照时点一致;revision 与 etcdutl snapshot status 记录的 revision 对齐,至少不包含快照后的写入;没有 NOSPACE、CORRUPT 等告警。
失败的判据是:成员反复退出、没有 leader 或 health 超时;键值缺失、顺序和内容与基线不一致;快照后的键仍然存在,说明启动的是旧数据目录或拿错快照;出现告警;恢复后仍有客户端向旧成员写入。
docker ps -a、容器日志、endpoint status、alarm list。容器 Running 不代表 etcd 已形成 leader。etcdutl snapshot status 的 revision、键数量、大小,与恢复后 endpoint status 和 get --prefix 的结果对照。差异明显时先查是不是拿错了快照或数据目录。--data-dir、成员名、token 和 peer URL。不要用 rm -rf 清掉旧目录来“重试”,那会破坏回滚和取证材料。EncryptionConfiguration 和静态加密密钥。恢复后 etcd 健康、kubectl 却连不上或 Secret 无法解密时,要查这些文件,而不是反复恢复数据。如果恢复后的成员无法启动,或验证发现拿错快照,先停止新容器,保留新卷和日志,再启动旧容器回到恢复前状态:
timeout 60 docker stop lab-etcd-restored 2>/dev/null || true
timeout 60 docker start lab-etcd
timeout 60 bash -c 'until docker exec lab-etcd etcdctl endpoint health; do sleep 2; done'
docker exec lab-etcd etcdctl get /lab/before
这条回滚只适用于旧数据目录本身仍然可用的情况。如果故障是逻辑损坏、误删或数据污染,回到旧目录等于回到坏状态,应改用另一份已校验的快照,而不是盲目回滚。生产环境回滚前还要确认没有业务已经向恢复后的集群写入;一旦写入,重新灌快照会产生冲突,必须先把新写入导出、隔离,再决定重新恢复还是人工核对。
如果快照损坏,停止所有成员,换一份校验通过的快照重新恢复,所有成员必须来自同一份快照。不要尝试拼接不同快照的数据目录,也不要在恢复过程中升级 etcd 或 Kubernetes。若证书或加密密钥丢失,先从离线备份恢复;无法恢复时按集群 PKI 重建流程处理,不要关闭证书校验来绕过问题。
实验结束后,确认恢复结果已验证、快照和记录已保存,再清理本实验的容器和卷:
timeout 60 docker rm -f lab-etcd lab-etcd-restored 2>/dev/null || true
timeout 60 docker volume rm lab-etcd-data lab-etcd-restored 2>/dev/null || true
rm -rf /tmp/lab-etcd-restore
恢复后的数据一致性检查包括:对比快照前与恢复后的完整键值文件;核对 /lab 键数量和 revision;确认快照后的写入和修改都已消失;检查告警和成员列表;如果是在 Kubernetes 环境,还要核对 Namespace、CRD、关键对象数量和 Secret 解密是否正常。所有差异都要能由“快照时点 + 可接受的丢失窗口”解释。
按成员、数据、快照、上层集群四个层次验证,所有可能阻塞的命令都加超时:
timeout 30 docker exec lab-etcd-restored etcdctl endpoint health
docker exec lab-etcd-restored etcdctl endpoint status -w table
docker exec lab-etcd-restored etcdctl alarm list
docker exec lab-etcd-restored etcdctl get /lab --prefix > /tmp/lab-etcd-restore/restored.txt
diff -u /tmp/lab-etcd-restore/backup/before.txt /tmp/lab-etcd-restore/restored.txt
docker exec lab-etcd-restored etcdctl get /lab/after | wc -l
docker exec lab-etcd-restored etcdctl get /lab --prefix --keys-only | grep -c .
endpoint status 只有一个 leader,成员列表完整。/lab 键值与快照前基线完全一致,快照后的键和修改都不存在。alarm list 为空,没有 NOSPACE、CORRUPT 等告警,磁盘空间充足。kubectl get --raw='/readyz/etcd' 返回 ok,节点、Namespace 和关键对象可读。EncryptionConfiguration 和静态加密密钥。缺少这些文件时 etcd 本身健康,但 Secret 数据无法解密;应从离线备份恢复加密配置和密钥。
小程序版
微信扫码,随时查命令