Kubernetes etcd 运维与灾备
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
本文缩写(英文全称与中文含义)
| 缩写 | 英文全称/名称 | 中文含义 |
|---|---|---|
| API | Application Programming Interface | 应用程序编程接口 |
| CA | Certificate Authority | 证书颁发机构 |
| CPU | Central Processing Unit | 中央处理器 |
| CRD | Custom Resource Definition | Kubernetes 自定义资源定义 |
| DNS | Domain Name System | 域名系统 |
| EKS | Elastic Kubernetes Service | AWS 托管 Kubernetes 服务 |
| GitOps | GitOps | 以 Git 保存期望状态、由自动化持续协调实际状态的运维方式 |
| I/O | Input/Output | 输入/输出 |
| IOPS | Input/Output Operations Per Second | 每秒输入输出操作数 |
| IP | Internet Protocol | 网际协议;IP 地址是网络寻址标识 |
| KMS | Key Management Service | 密钥管理服务 |
| PKI | Public Key Infrastructure | 公钥基础设施 |
| PV | Persistent Volume | 持久卷 |
| RBAC | Role-Based Access Control | 基于角色的访问控制 |
| RPO | Recovery Point Objective | 恢复点目标,可接受的数据丢失时间范围 |
| RTO | Recovery Time Objective | 恢复时间目标,可接受的恢复耗时 |
| SAN | Subject Alternative Name | 证书主题备用名称,用于声明域名或 IP |
| SLO | Service Level Objective | 服务等级目标 |
| TLS | Transport Layer Security | 传输层安全协议 |
适用于有控制面主机权限的自建 Kubernetes。以下以 kubeadm 静态 Pod、三成员 etcd 为例,地址和路径需按实际清单调整;托管 EKS/GKE 控制面不执行这些命令。
1. 确认连接与健康状态#
在控制面主机的 Bash 中执行。先检查 /etc/kubernetes/manifests/etcd.yaml 的镜像版本、--data-dir、挂载目录及 TLS 参数,再准备匹配版本的 etcdctl 和 etcdutl。
export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/healthcheck-client.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/healthcheck-client.key
etcdctl member list --write-out=table
etcdctl endpoint status --cluster --write-out=table
etcdctl endpoint health --cluster
etcdctl alarm list--cluster 使用成员公布的客户端地址,当前主机必须能访问且证书 SAN 匹配。验收:3 个成员健康、恰好一个 Leader、无告警,Raft applied index 在持续写入时可短暂不同,但不应长期落后。
不批量导出键值来“巡检”,其中可能包含 Secret。检查 Kubernetes 对象使用 kubectl。
2. 在线快照与备份策略#
快照从一个健康 endpoint 获取;etcdctl 保存,etcdutl 检查和恢复。不要用复制运行中数据目录代替一致性快照。
set -euo pipefail
umask 077
BACKUP_DIR=/var/backups/etcd
install -d -m 0700 "$BACKUP_DIR"
SNAPSHOT="$BACKUP_DIR/etcd-$(date -u +%Y%m%dT%H%M%SZ).db"
etcdctl --endpoints=https://127.0.0.1:2379 snapshot save "$SNAPSHOT"
etcdutl snapshot status "$SNAPSHOT" --write-out=table
(cd "$BACKUP_DIR" && sha256sum "$(basename "$SNAPSHOT")" > "$(basename "$SNAPSHOT").sha256")自动化任务需显式设置上述 TLS 环境变量,避免重叠执行,失败立即告警。上传到加密、受限访问的异机存储后校验对象完整性;不要将唯一副本留在控制面磁盘。
| 项目 | 实施要求 |
|---|---|
| 周期 | 按 RPO 设置,例如每 15 分钟;备份失败或传输延迟会扩大实际 RPO |
| 保留 | 示例:最近 48 小时保留全部快照,日备份保留 30 天;按容量与合规调整 |
| 配套资产 | Kubernetes/etcd 版本、成员名/IP、静态 Pod 清单、PKI、加密配置及 KMS 恢复权限 |
| 演练 | 在隔离环境恢复并验证对象可读;记录恢复耗时作为 RTO 依据 |
| 业务数据 | PV、数据库、对象存储单独备份,协调应用一致性 |
快照可能包含敏感数据,应限制读取权限。KMS 不可用或旧密钥已销毁时,只有快照也可能无法解密 Kubernetes 资源。
3. 先选择正确的故障处理#
| 故障 | 操作 |
|---|---|
| 3 个成员中 1 个不可用,另外 2 个健康 | 修复或替换该成员,保持现有集群数据 |
| 多数成员暂时不可达 | 优先恢复网络、磁盘、证书或进程,不立即回滚数据 |
| 多数成员永久丢失 | 隔离旧集群,从已验证快照重建全部成员 |
| 单个 Kubernetes 对象误删 | 优先通过 GitOps 或对象级备份恢复,避免全局回滚 |
| 大范围逻辑破坏 | 选择故障前快照,评估丢失写入及外部系统一致性后整体恢复 |
4. 三节点灾备恢复流程#
本例在原三台主机恢复;成员名为 cp1/cp2/cp3,peer 地址为 10.0.1.10/10.0.2.10/10.0.3.10:2380。变更 IP 时,先更新证书 SAN、防火墙和 API Server 的 etcd endpoint。
4.1 冻结与隔离#
- 暂停发布、GitOps 自动同步和入口变更,记录故障时间、快照时间及预期丢失窗口。
- 在所有控制面节点将
kube-apiserver.yaml移出静态 Pod 目录,确认 API Server 容器已停止;同时暂停 controller-manager、scheduler,防止恢复过程中自动协调。 - 在所有 etcd 节点将
etcd.yaml移出该目录,确认 etcd 容器和监听端口已停止。使用crictl ps检查,不能只依赖已不可用的 API。 - 隔离任何可能重新上线的旧成员;保留原数据目录和清单,禁止新旧集群并行接受请求。
清单备份必须放在 /etc/kubernetes/manifests/ 之外,仅改成 .bak 仍可能被 kubelet 读取。外部 etcd 则停止对应 systemd 服务。参考 Kubernetes 恢复说明。
4.2 在每个成员离线恢复#
将同一个快照与校验文件安全复制到三台主机。保留原文件名;校验文件记录相对文件名,可跨主机验证。校验和应来自受限备份记录,不能与损坏文件一起重新生成。以下命令在每台主机执行一次,分别修改 MEMBER_NAME 和 PEER_IP;目标目录必须不存在。
set -euo pipefail
MEMBER_NAME=cp1
PEER_IP=10.0.1.10
INITIAL_CLUSTER='cp1=https://10.0.1.10:2380,cp2=https://10.0.2.10:2380,cp3=https://10.0.3.10:2380'
RESTORE_TOKEN=etcd-dr-20260922
SNAPSHOT=/var/backups/etcd/REPLACE_ORIGINAL_SNAPSHOT_FILENAME.db
(cd "$(dirname "$SNAPSHOT")" && sha256sum -c "$(basename "$SNAPSHOT").sha256")
etcdutl snapshot status "$SNAPSHOT" --write-out=table
etcdutl snapshot restore "$SNAPSHOT" --name "$MEMBER_NAME" --data-dir /var/lib/etcd-restored --initial-cluster "$INITIAL_CLUSTER" --initial-advertise-peer-urls "https://$PEER_IP:2380" --initial-cluster-token "$RESTORE_TOKEN" --bump-revision 1000000000 --mark-compacted三节点使用相同 cluster 列表、token 和 Revision bump,成员名及 peer 地址各不相同。1000000000 是示例增量,应大于“快照年龄 × 峰值 Revision 增长率”并留余量。--mark-compacted 迫使 Watch 客户端重新同步。不要使用 --skip-hash-check 绕过损坏快照。参数依据 etcd 恢复文档。
4.3 启动 etcd,再启动控制面#
- 检查恢复目录属主、权限和 SELinux 上下文与原目录要求一致。
- 修改移出的 etcd 清单:将数据卷
hostPath.path改为/var/lib/etcd-restored;容器内mountPath与--data-dir保持一致。例如二者仍为/var/lib/etcd,只是宿主机路径改变。核对成员名、peer 地址、cluster 列表和 token,与恢复命令一致。 - 在三台主机放回 etcd 清单,等待形成 quorum。执行第一节的健康检查,确认全部成员正常后才继续。
- 放回各节点 API Server 清单,确认原 PKI、加密配置和 KMS 可用;随后恢复 controller-manager、scheduler,重启其他使用 Watch 缓存的控制器,使其重新同步。
- 完成下面的验收,再恢复 GitOps、发布和业务流量。若失败,保持冻结并排障;不要让旧数据目录与恢复集群混用。
4.4 验收与业务对账#
kubectl get --raw='/readyz?verbose'
kubectl get nodes
kubectl get pods -A
kubectl get pvc -A
kubectl get events -A --sort-by=.metadata.creationTimestamp
kubectl create namespace etcd-dr-check
kubectl -n etcd-dr-check create configmap write-check --from-literal=status=ok
kubectl -n etcd-dr-check get configmap write-check -o jsonpath='{.data.status}'
kubectl delete namespace etcd-dr-check确认关键 CRD、RBAC 和受加密资源可由授权工作负载正常读取,不将 Secret 值打印到日志。执行业务读写、DNS、Ingress、存储挂载及控制器收敛检查。快照之后的资源变更会丢失,但云负载均衡器、PV 和外部数据库不会随之回滚,需对账孤立资源、重复任务及订单状态。最后生成新快照并记录实际 RPO/RTO。
5. 日常维护与成员替换#
历史压缩与碎片整理#
先核对 API Server 的 --etcd-compaction-interval 与现有自动压缩策略,避免重复配置。只有确定保留窗口后才手工执行:
# 用经评估的历史 Revision 替换占位值,不要盲目压缩到最新版本。
COMPACT_REV='<保留窗口之前的 Revision>'
etcdctl compact "$COMPACT_REV"
# 一次只处理一个成员:先 follower,确认恢复健康后再处理下一个。
etcdctl --endpoints=https://10.0.2.10:2379 --command-timeout=60s defrag
etcdctl endpoint health --cluster在线 Defrag 会阻塞该成员读写,安排低峰期,Leader 最后处理。NOSPACE 时先控制增长来源,经 Kubernetes API 清理不需要的资源,再压缩与逐成员 Defrag;确认低于配额后执行 etcdctl alarm disarm,最后通过 Kubernetes API 验证写入。不要直接删除 /registry/ 数据。见 etcd 维护文档。
替换永久故障成员#
前提:其余投票成员仍构成 quorum,并已完成快照。每次只替换一个成员;kubeadm 管理的控制面优先遵循其节点移除/加入流程,避免与手工成员变更重复。
# 先核对 member list;这些 ID 是十六进制占位值。
FAILED_MEMBER_ID='<故障成员 ID>'
etcdctl member remove "$FAILED_MEMBER_ID"
etcdctl member add cp4 --peer-urls=https://10.0.4.10:2380 --learner在新节点配置有效的 peer/client TLS、空数据目录,按 member add 输出设置成员列表并使用 initial-cluster-state=existing 启动。等待日志追平后执行:
NEW_MEMBER_ID='<新 learner 的 ID>'
etcdctl member promote "$NEW_MEMBER_ID"
etcdctl member list --write-out=table
etcdctl endpoint health --clusterLearner 不参与投票;未追平时 Promote 会被拒绝,等待排障后重试,不关闭严格检查。禁止让已移除成员携带旧数据目录重新加入。见成员变更说明。
升级时先验证 Kubernetes 兼容范围并备份,按对应 etcd 版本升级指南逐成员滚动升级,每步检查健康;不要同时重启多数成员或直接跳过 minor 版本。
6. 监控与排障#
通过受限网络采集 /metrics,不要公开暴露。指标见官方监控文档,阈值应结合磁盘、网络基线和控制面 SLO 制定。
| 信号或现象 | 优先检查 |
|---|---|
etcd_server_has_leader = 0 |
quorum、2380 连通性、成员进程及证书 |
etcd_server_leader_changes_seen_total 短期频繁增长 |
磁盘 fsync、网络抖动、CPU 饥饿 |
etcd_disk_wal_fsync_duration_seconds、etcd_disk_backend_commit_duration_seconds 延迟升高 |
磁盘 IOPS/延迟、容量、同机 I/O 竞争 |
etcd_mvcc_db_total_size_in_bytes 接近 etcd_server_quota_backend_bytes |
与 etcd_mvcc_db_total_size_in_use_in_bytes 对比,区分有效数据增长与碎片 |
etcd_server_proposals_pending 持续升高 |
写入压力、Leader、网络与磁盘瓶颈 |
x509 错误 |
证书有效期、CA、SAN、主机时间;kubeadm 可用 kubeadm certs check-expiration |
request timed out / context deadline exceeded |
先确认健康、quorum 与延迟,不先增大超时掩盖故障 |
required revision has been compacted |
Watch 重新 List 后重建;长期循环检查客户端重试逻辑 |
| 快照失败或备份年龄超限 | 磁盘空间、TLS、定时任务环境、上传状态与告警链路 |