etcd生产运维与灾难恢复完整指南
etcd 是 Kubernetes 控制面的事实来源。Deployment、Secret、Lease、CRD和控制器状态最终都依赖它。etcd 进程仍在运行并不代表集群健康:磁盘同步延迟、空间配额耗尽、成员失去多数派或错误恢复,都可能让API写入停顿,甚至造成永久数据分叉。
本文面向自建或负责底层控制面的运维团队。托管Kubernetes通常不允许直接操作etcd,应使用云厂商提供的备份与恢复能力。所有成员变更、快照恢复和强制动作都必须先在同版本隔离环境演练。
一、先理解一致性与多数派
etcd 使用Raft复制日志,写入需要多数成员确认。常见奇数成员容错关系:
| 成员数 | 需要多数 | 可容忍永久故障 |
|---|---|---|
| 1 | 1 | 0 |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
增加到偶数成员不会增加对应容错能力,例如4成员仍只能容忍1个故障,却增加复制开销。Kubernetes常见3或5成员。成员应分布在独立故障域,但网络往返和磁盘延迟必须满足控制面要求;跨越高延迟地域的单个Raft集群通常会牺牲写入可用性。
二、拓扑与硬件基线
- 使用低延迟、可靠的本地SSD或明确保证fsync性能的块存储;
- etcd数据盘与高I/O日志、容器层、备份压缩任务隔离;
- CPU不能长期被控制面其他组件抢占;
- 成员间网络稳定、低延迟、低丢包;
- 时间同步、DNS和证书生命周期受监控;
- 数据目录有容量预留,不依赖磁盘接近满时再扩容;
- 快照写往独立故障域,不与数据盘同生共死。
etcd最敏感的往往不是顺序吞吐,而是尾部fsync延迟。虚拟化存储“平均很快”但周期性停顿,也会触发选主和请求超时。
三、TLS与访问边界
客户端和成员间通信均启用TLS,分别管理server、client和peer证书。证书包含正确SAN,私钥权限最小,并在到期前完成滚动轮换。不要为了处理证书错误临时改为明文监听公网或业务网卡。
export ETCDCTL_API=3
etcdctl --endpoints=https://10.0.0.11:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
endpoint status --write-out=table
生产端点只对控制面和受控运维网络开放。快照包含Secret等敏感数据,必须加密、限制访问、记录下载和恢复操作。
四、日常健康检查不能只看进程
etcdctl --endpoints=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379 \
--cacert=ca.crt --cert=client.crt --key=client.key \
endpoint health --cluster
etcdctl --endpoints=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379 \
--cacert=ca.crt --cert=client.crt --key=client.key \
endpoint status --cluster --write-out=table
etcdctl --endpoints=https://10.0.0.11:2379 \
--cacert=ca.crt --cert=client.crt --key=client.key alarm list
检查leader、Raft term、已提交和已应用索引、数据库大小、是否存在learner、错误和告警。不同成员索引短暂有差异属正常,但持续扩大需要调查网络或磁盘。
五、核心监控指标
重点关注:
- leader变化和无leader时长;
- 提交到应用延迟、proposal pending与failed;
- WAL fsync和backend commit高分位延迟;
- peer往返延迟和发送失败;
- 数据库实际大小、总分配大小和配额比例;
- gRPC请求速率、失败和慢请求;
- 进程CPU、RSS、文件句柄和磁盘空间;
- Kubernetes API Server请求延迟与etcd指标的时间关联。
告警不应只写“etcd down”。leader频繁变化、磁盘P99恶化、空间超过阈值和成员索引持续落后,都应在写入完全停止前处理。
六、定期快照与校验
snapshot="/backup/etcd/snapshot-$(date +%Y%m%d-%H%M%S).db"
etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=ca.crt --cert=client.crt --key=client.key \
snapshot save "$snapshot"
etcdutl snapshot status "$snapshot" --write-out=table
快照任务应检查退出码、文件大小、revision和hash,再复制到独立存储。仅复制正在使用的数据目录并不等于一致快照。保留至少日、周、月多层恢复点,并监控最近成功时间是否满足RPO。
恢复演练必须使用快照副本,验证可以启动、成员健康、Kubernetes API可读写、关键CRD存在且Secret可解密。
七、历史版本、压缩与碎片整理
etcd保留键的历史版本以支持watch和历史读取,长期不压缩会持续增长。压缩删除旧revision的逻辑历史,但物理文件可能不会立即缩小;defrag才回收成员本地数据库的空闲页。
revision=$(etcdctl endpoint status --write-out=json | jq -r '.[0].Status.header.revision')
compact_to=$((revision - 10000))
etcdctl compact "$compact_to"
etcdctl --endpoints=https://10.0.0.11:2379 \
--cacert=ca.crt --cert=client.crt --key=client.key defrag
生产应优先启用经过验证的自动压缩策略。defrag逐成员进行,一次只处理一个非leader成员并观察,再处理其他成员,最后视情况处理leader。它可能阻塞当前成员,不应全成员并行执行。
八、空间配额与NOSPACE告警
当后端超过配额时,etcd会触发NOSPACE告警并限制写入。处置步骤不是直接扩大配额:
- 确认各成员数据库和磁盘空间;
- 找出异常增长来源,例如大量Events、Lease、自定义资源或控制器热循环;
- 在满足watch保留需求的前提下compact;
- 逐成员defrag;
- 确认空间恢复后解除告警;
- 修复增长源并重新评估配额。
etcdctl alarm list
etcdctl alarm disarm
只有确认空间已实际释放且根因受控后才解除告警,否则写入很快再次停止。
九、成员替换的安全步骤
单成员永久损坏但仍有多数派时,优先替换而非全量恢复:
etcdctl member list --write-out=table
etcdctl member remove MEMBER_ID
etcdctl member add etcd-3 --peer-urls=https://10.0.0.13:2380
随后在新节点使用全新数据目录和命令返回的初始集群参数启动。不要把旧损坏目录原样挂回。一次只替换一个成员,等待其追平并通过健康检查后再进行下一步。
成员增删是集群配置变更,不要在失去多数派后继续随意remove。先确认剩余拓扑、备份和恢复方案。
十、证书轮换与滚动维护
轮换前确认新旧CA信任重叠、SAN完整、所有成员时间正确。建议:
- 备份快照与静态Pod清单;
- 更新一个非leader成员;
- 验证peer和client通信、索引追平;
- 逐成员滚动;
- 验证API Server连接;
- 观察完整业务周期后再移除旧信任。
不要同时重启超过容错数的成员。维护窗口内持续监控多数派和API请求。
十一、从快照恢复的核心原则
恢复快照会创建新的逻辑集群,而不是简单把文件复制回原目录。使用 etcdutl snapshot restore 为每个成员生成独立数据目录,明确成员名称、peer URL和initial-cluster。
etcdutl snapshot restore snapshot.db \
--name=etcd-1 \
--data-dir=/var/lib/etcd-restored \
--initial-cluster=etcd-1=https://10.0.0.11:2380,etcd-2=https://10.0.0.12:2380,etcd-3=https://10.0.0.13:2380 \
--initial-advertise-peer-urls=https://10.0.0.11:2380
为其余成员分别执行并使用对应name、data-dir和URL。停止旧集群、保留旧数据目录只读副本,切换静态Pod或服务配置后再启动。具体参数和revision处理以所用etcd版本官方恢复文档为准。
十二、Kubernetes恢复后的连锁效应
etcd还原到旧时间点后,现实世界可能已经变化:
- 已删除的Pod、Job或Node对象重新出现;
- 云负载均衡器、磁盘和IP与对象状态不一致;
- Lease和领导选举回到旧状态;
- ServiceAccount令牌、证书和Secret可能已轮换;
- Operator可能依据旧spec再次执行外部动作;
- GitOps会尝试把集群收敛到当前仓库状态。
恢复后先隔离外部写操作,检查控制器和Operator,再分阶段恢复。不能只看到API Server启动就宣布成功。
十三、失去多数派时的决策
失去多数派后不能通过启动一个旧副本安全“凑数”。先冻结所有变更并收集:存活成员、数据目录、最新快照、revision、证书、静态Pod配置和基础设施状态。
选择:
- 能恢复原多数派:修复网络、电源或磁盘后让成员重新加入;
- 原成员永久丢失:从已验证的最新快照恢复新集群;
- 无有效快照:只能基于剩余数据和官方灾难恢复流程评估,必须接受可能的数据丢失。
不要让两组持有不同历史的成员同时对外服务,避免脑裂式数据分叉。
十四、性能异常排查
顺序:
- 对齐API Server延迟与etcd请求延迟;
- 检查leader变化、proposal和慢请求;
- 检查WAL fsync、backend commit和磁盘队列;
- 检查成员网络丢包、RTT和MTU;
- 检查CPU抢占、内存压力和宿主机停顿;
- 检查资源数量、Events和控制器热循环;
- 检查数据库大小、压缩与碎片;
- 在修复基础设施后再调超时或配额。
盲目提高heartbeat、election timeout或API超时可能掩盖基础设施问题,并延长真实故障发现时间。
十五、维护周期建议
| 周期 | 工作 |
|---|---|
| 持续 | 健康、leader、延迟、空间、磁盘与证书监控 |
| 每日 | 快照、状态校验、异地复制和失败告警 |
| 每周 | 容量趋势、慢请求、成员差异和异常资源增长复核 |
| 每月 | 隔离恢复抽检、权限和备份保留检查 |
| 每季度 | 完整控制面恢复、成员替换和证书轮换演练 |
| 升级前 | 快照、兼容矩阵、回滚和恢复验证 |
周期只是假设,实际频率由RPO、变更速度和合规要求决定。
十六、生产验收清单
- [ ] 使用3或5个成员并跨独立故障域合理分布;
- [ ] 数据盘fsync高分位延迟满足要求且有告警;
- [ ] client和peer通信均启用TLS,证书受监控;
- [ ] 每日快照已校验并复制到独立故障域;
- [ ] 自动压缩和逐成员defrag流程经过验证;
- [ ] NOSPACE、失去leader和索引落后有Runbook;
- [ ] 成员替换一次一个并等待追平;
- [ ] 恢复环境记录版本、证书、清单与启动参数;
- [ ] 恢复后检查外部资源和控制器副作用;
- [ ] 最近一次完整恢复演练满足RPO与RTO。
十七、官方参考
- etcd Operations Guide: Maintenance
- etcd Disaster Recovery
- etcd Runtime Reconfiguration
- Operating etcd clusters for Kubernetes
etcd运维的核心不是熟记命令,而是始终保护多数派、数据历史和可验证恢复点。任何“快速修复”若破坏这三项,都可能把短暂控制面故障变成不可逆的数据事故。