主题
RKE2 三 control-plane 节点全部宕机后的集群灾后恢复记录
记录时间:2026-07-13
涉及集群:RKE2 v1.35.6+rke2r1(Rocky Linux 9.8)
涉及节点:
192.168.122.78(szc122078)—— 原首节点 / 恢复后的单节点 etcd192.168.122.69(szc122069)—— 原 control-plane/etcd,恢复中仍异常192.168.122.136(szc122136)—— 新加入/重新加入的 control-plane/etcd
1. 故障背景
原集群为 3 节点 control-plane/etcd 部署(78 / 69 / 136)。因全部 etcd 节点同时失去 quorum,三个节点上的 rke2-server 均无法启动,反复报错:
text
error "etcdserver: request timed out"
transport: authentication handshake failed: context deadline exceeded
dial tcp 127.0.0.1:2379: connect: connection refused集群 API 完全不可用。
2. 环境信息
| 项目 | 内容 |
|---|---|
| RKE2 版本 | v1.35.6+rke2r1 |
| 操作系统 | Rocky Linux 9.8 (Blue Onyx) |
| 网络 CIDR | cluster-cidr: 10.12.0.0/16,service-cidr: 10.13.0.0/16 |
| 私有镜像仓库 | 192.168.122.156:30000(registries.yaml 中仅配置了该 endpoint,未覆盖 docker.io) |
| 本地镜像包 | /var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst |
| 首节点 server | https://192.168.122.78:9345 |
| 加入 token | xxx |
2.1 关键配置文件示例
/etc/rancher/rke2/config.yaml(以 136 为例)
yaml
server: https://192.168.122.78:9345
token: xxx
kube-proxy-arg:
- "proxy-mode=ipvs"
node-name: 192.168.122.136
data-dir: /var/lib/rancher/rke2
cluster-cidr: 10.12.0.0/16
service-cidr: 10.13.0.0/16注:
disable-scheduler-node-taints: true不是 RKE2 v1.35.6 支持的参数,已在 136 的配置中删除。
/etc/rancher/rke2/registries.yaml
yaml
mirrors:
"192.168.122.156:30000":
endpoint:
- "http://192.168.122.156:30000"
configs:
"192.168.122.156:30000":
tls:
insecure_skip_verify: true3. 已执行的恢复步骤
3.1 全节点清理残留进程
在三节点上依次执行(确保没有残留的 etcd / kube-apiserver 进程或旧挂载):
bash
rke2-killall.sh3.2 在 78 上强制单节点恢复 etcd
3.2.1 备份 etcd 数据
bash
mkdir -p /var/lib/rancher/rke2/server/db/etcd.bak.$(date +%Y%m%d%H%M%S)
cp -a /var/lib/rancher/rke2/server/db/etcd/* /var/lib/rancher/rke2/server/db/etcd.bak.*/3.2.2 修改 etcd 配置启用 force-new-cluster
编辑 /var/lib/rancher/rke2/server/db/etcd/config,追加:
yaml
force-new-cluster: true该配置会忽略旧成员信息,将原三节点 etcd 数据强制降级为单节点集群。
3.2.3 移除失效 etcd 成员
使用 etcdctl 连接到本地 etcd,移除 69 和 136 的旧成员记录:
bash
/var/lib/rancher/rke2/agent/containerd/.../etcdctl \
--cacert /var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
--cert /var/lib/rancher/rke2/server/tls/etcd/server-client.crt \
--key /var/lib/rancher/rke2/server/tls/etcd/server-client.key \
--endpoints https://127.0.0.1:2379 member list -w table
/var/lib/rancher/rke2/agent/containerd/.../etcdctl \
--cacert /var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
--cert /var/lib/rancher/rke2/server/tls/etcd/server-client.crt \
--key /var/lib/rancher/rke2/server/tls/etcd/server-client.key \
--endpoints https://127.0.0.1:2379 member remove <旧成员 ID>3.2.4 重启 rke2-server
bash
systemctl restart rke2-server等待后 78 节点恢复为单节点 etcd 集群,API 重新可用,节点状态变为 Ready。
3.2.5 恢复后移除 force-new-cluster
待 78 稳定后,从 /var/lib/rancher/rke2/server/db/etcd/config 中删除:
yaml
force-new-cluster: true并再次重启 rke2-server。
3.3 重新加入 136
- 在 136 上确认
/etc/rancher/rke2/config.yaml中server和token正确。 - 清理无效参数
disable-scheduler-node-taints。 - 重启
rke2-server:
bash
systemctl restart rke2-server- 离线环境首次启动需要导入本地镜像包(约 7–10 分钟),观察日志:
bash
journalctl -u rke2-server -f- 镜像导入完成后,136 成功加入并变为
Ready。
4. 当前状态(截至 2026-07-13)
4.1 节点状态
192.168.122.78:Ready,单节点 etcd 已恢复,K8s API 可用。192.168.122.136:Ready,已成功重新加入集群。192.168.122.69:rke2-server仍在activating,尚未 Ready。
4.2 etcd 成员列表(从 78 查询)
text
+------------------+---------+-------------------------+-----------------------------+-----------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-------------------------+-----------------------------+-----------------------------+------------+
| 69eda8d743dc6cf3 | started | 192.168.122.69-7660041d | https://192.168.122.69:2380 | https://192.168.122.69:2379 | false |
| be8909c697309581 | started | 192.168.122.78-fe8d15eb | https://192.168.122.78:2380 | https://192.168.122.78:2379 | false |
+------------------+---------+-------------------------+-----------------------------+-----------------------------+------------+注:136 已 Ready 但未出现在上述 member list 中,需在下次继续排查时重新确认其 etcd 成员身份(可能为 learner 或加入流程尚未同步)。
4.3 69 上的 etcd 日志关键现象
text
{"level":"warn","ts":"2026-07-13T16:52:34.342886Z","caller":"etcdserver/server.go:1846","msg":"failed to publish local member to cluster through raft","local-member-id":"69eda8d743dc6cf3","local-member-attributes":"{Name:192.168.122.69-7660041d ClientURLs:[https://192.168.122.69:2379]}","publish-timeout":"15s","error":"etcdserver: too many requests"}此前还出现过:
text
transport: authentication handshake failed: context deadline exceeded
dial tcp 127.0.0.1:2379: connect: connection refused4.4 根本原因推测
- 69 上的 etcd 已经以旧
member ID(69eda8d743dc6cf3)启动,并被 78 的 etcd 视为成员。 - 本地 etcd 数据目录
/var/lib/rancher/rke2/server/db/etcd仍保留旧的集群元数据,可能与重置后的单节点集群状态冲突。 too many requests可能是集群正在尝试同步大量数据,也可能是 raft 状态异常导致 69 无法完成 publish。
5. 下次继续修复 69 需要的信息与步骤
5.1 首先确认 136 的 etcd 成员状态
在 78 上执行:
bash
/var/lib/rancher/rke2/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/3/fs/usr/local/bin/etcdctl \
--cacert /var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
--cert /var/lib/rancher/rke2/server/tls/etcd/server-client.crt \
--key /var/lib/rancher/rke2/server/tls/etcd/server-client.key \
--endpoints https://127.0.0.1:2379 member list -w table同时确认 K8s 节点状态:
bash
kubectl get nodes -o wide
kubectl get componentstatus5.2 观察 69 的实时日志
bash
journalctl -u rke2-server -f查看 etcd 容器日志:
bash
export PATH=/var/lib/rancher/rke2/bin:$PATH
export CONTAINERD_ADDRESS=/run/k3s/containerd/containerd.sock
# 找到 etcd 容器 ID
ctr -a -n k8s.io containers list | grep etcd
# 或
crictl ps | grep etcd
# 查看日志
crictl logs <etcd-container-id> --tail 1005.3 推荐修复方案 A:清理 69 的 etcd 数据后重新加入
如果 69 持续无法完成 raft publish 或证书/成员身份冲突,最稳妥的方式是:
- 在 78 上确认 69 的成员 ID 并移除(如尚未移除):
bash
etcdctl --cacert ... --cert ... --key ... --endpoints https://127.0.0.1:2379 member remove 69eda8d743dc6cf3- 在 69 上停止服务并清理:
bash
systemctl stop rke2-server
rke2-killall.sh
# 备份后删除旧 etcd 数据
mv /var/lib/rancher/rke2/server/db/etcd /var/lib/rancher/rke2/server/db/etcd.bak.$(date +%Y%m%d%H%M%S)- 确认 69 的
/etc/rancher/rke2/config.yaml:
yaml
server: https://192.168.122.78:9345
token: xxx
kube-proxy-arg:
- "proxy-mode=ipvs"
node-name: 192.168.122.69
data-dir: /var/lib/rancher/rke2
cluster-cidr: 10.12.0.0/16
service-cidr: 10.13.0.0/16- 启动服务:
bash
systemctl start rke2-server
journalctl -u rke2-server -f- 等待本地镜像导入完成(离线环境约 7–10 分钟),然后确认:
bash
kubectl get nodes -o wide
kubectl get componentstatus
etcdctl ... member list -w table5.4 备选方案 B:先等待同步完成
如果 69 的 etcd 日志只是 too many requests,可以尝试:
- 保持
rke2-server运行 10–20 分钟,观察是否完成数据同步。 - 检查 78 与 69 之间的网络:
bash
# 在 69 上
timeout 5 bash -c '</dev/tcp/192.168.122.78/9345'
timeout 5 bash -c '</dev/tcp/192.168.122.78/6443'
timeout 5 bash -c '</dev/tcp/192.168.122.78/2379'
timeout 5 bash -c '</dev/tcp/192.168.122.78/2380'- 如果同步完成且节点 Ready,则无需清理数据。
5.5 检查证书/token 有效性
如果仍出现 authentication handshake failed,需检查:
- 三节点
/var/lib/rancher/rke2/server/token是否一致。 - 时间是否同步(建议启用 NTP)。
- 防火墙是否放行 2379/2380/9345/6443/10250/8472/4789 等端口。
6. 已知注意事项
离线镜像拉取会超时:RKE2 启动时仍会尝试从
docker.io拉取rke2-images-all.linux-amd64.txt中缺失的镜像,失败后才会使用本地 tar 包。不影响最终启动,但会延长启动时间。后续建议将缺失镜像推送到私有仓库并在registries.yaml中配置docker.iomirror。force-new-cluster是破坏性操作:仅在全部 etcd 节点都不可用、且无其他备份时使用。恢复完成后一定要记得从etcd/config中移除该参数并重启。清理 etcd 数据前必须备份:删除
/var/lib/rancher/rke2/server/db/etcd会导致该节点丢失本地 etcd 成员信息,重新加入时会生成新的 member ID。恢复期间尽量减少对集群的写操作:在 69 未完全恢复前,避免大量 Pod 调度或资源创建,以防再次触发 quorum 相关异常。
7. 关键文件路径速查
| 路径 | 说明 |
|---|---|
/etc/rancher/rke2/config.yaml | RKE2 配置文件 |
/etc/rancher/rke2/registries.yaml | 镜像仓库配置 |
/var/lib/rancher/rke2/server/db/etcd/config | etcd 静态 Pod 配置 |
/var/lib/rancher/rke2/server/db/etcd/member | etcd 数据目录 |
/var/lib/rancher/rke2/server/db/etcd.bak.* | 备份目录 |
/var/lib/rancher/rke2/server/token | 集群 token 文件 |
/var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst | 离线镜像包 |
/var/lib/rancher/rke2/agent/containerd/.../etcdctl | etcdctl 可执行文件(overlayfs 路径可能变化) |
6. 继续排查与修复(2026-07-14)
6.1 实际状态与文档记录的差异
2026-07-14 继续排查时发现,文档中“78 Ready / 136 Ready / 69 仍在 activating”的状态已不复存在,三节点实际均为异常:
| 节点 | 实际状态 |
|---|---|
192.168.122.78 | rke2-server 处于 activating 并反复 crashloop,报错 failed to reconcile with local datastore: context deadline exceeded |
192.168.122.69 | rke2-server 处于 activating,尝试加入集群 |
192.168.122.136 | rke2-server 已停止(inactive) |
进一步检查 78 上的 etcd:
- etcd 进程仍在运行,端口 2379/2381 开放;
/health返回{"health":"false","reason":"RAFT NO LEADER"};endpoint status显示IS LEADER: false;- etcd 日志中仍在向旧成员
69eda8d743dc6cf3(192.168.122.69)发送MsgPreVote; - 之前的
force-new-cluster: true未生效,因为 RKE2 启动时会重新生成/var/lib/rancher/rke2/server/db/etcd/config,覆盖手动追加的参数。
6.2 正确的单节点恢复方式:使用 cluster-reset
RKE2 原生支持灾难恢复参数 cluster-reset,它会内部为 etcd 设置 force-new-cluster 并创建新的单节点集群。步骤如下:
- 三节点全部停止并清理残留进程:
bash
systemctl stop rke2-server
rke2-killall.sh- 在 78 上启用
cluster-reset:
bash
echo "cluster-reset: true" >> /etc/rancher/rke2/config.yaml
systemctl start rke2-server启动后日志会出现 Starting etcd for new cluster, cluster-reset=true,服务会执行完重置后自动退出一次,systemd 会再次启动它。
- 重置完成后移除该参数并再次启动:
bash
sed -i "/^cluster-reset:/d" /etc/rancher/rke2/config.yaml
systemctl start rke2-server注意:直接修改
/var/lib/rancher/rke2/server/db/etcd/config追加force-new-cluster: true在 RKE2 v1.35.6 中无效,RKE2 会重新生成该文件。
6.3 重新加入其他 control-plane 节点
6.3.1 清理节点并单台加入
etcd v3.6 默认最多只允许 一个 learner,若两台节点同时加入会报 too many learner members in cluster,并导致 78 的 etcd 被拖慢甚至整个集群 NotReady。因此必须逐台加入。
以 69 为例:
bash
# 在 69 上
systemctl stop rke2-server
rke2-killall.sh
mv /var/lib/rancher/rke2/server/db/etcd /var/lib/rancher/rke2/server/db/etcd.bak.$(date +%Y%m%d%H%M%S)
# 确认 /etc/rancher/rke2/config.yaml 中 server 与 token 正确
systemctl start rke2-server离线环境下,首次启动需要逐镜像从 docker.io 超时回退到本地 tar 包,耗时约 12–15 分钟。期间日志会持续出现:
text
Pulling image docker.io/rancher/...
Failed to test etcd connection: ... dial tcp 127.0.0.1:2379: connect: connection refused
Pod for etcd not synced (pod sandbox not found), retrying这是正常现象,等待镜像导入完成即可。
6.3.2 等待 learner 晋升为 voter
69 加入后首先在 etcd member list 中显示为 IS LEARNER: true:
text
| ebbf137c972248a6 | started | 192.168.122.69-b98d504f | https://192.168.122.69:2380 | https://192.168.122.69:2379 | true |此时 78 的 etcd 负载会显著上升,kubectl get nodes 可能短暂全部显示 NotReady,/health 也可能偶发超时。需保持耐心等待同步完成,直到该成员 IS LEARNER 变为 false:
text
| ebbf137c972248a6 | started | 192.168.122.69-b98d504f | https://192.168.122.69:2380 | https://192.168.122.69:2379 | false |6.3.3 再加入下一台节点
待 69 完全成为 voter、78/69 均 Ready 后,再对 136 执行同样的清理和启动流程。
6.4 关键注意事项
- 不要同时启动多个待加入的 control-plane 节点:etcd 单 learner 限制会导致加入失败并拖垮现有 etcd。
cluster-reset会重置 token/证书:虽然本例中重置后 token 与之前相同,但理论上应重新从 78 的/var/lib/rancher/rke2/server/token获取最新 token。- 离线镜像导入耗时较长:RKE2 会依次尝试从
docker.io拉取每个镜像并超时,然后才使用本地 tar 包。整个过程在虚拟机/慢磁盘上可能超过 10 分钟。 - learner 同步期间节点状态可能全部 NotReady:这是 etcd 高负载导致的临时现象,不要急于重启服务,避免进一步扰乱 raft 状态。
- 清理 etcd 数据前务必备份:本例中已使用
mv ... etcd.bak.<时间戳>保留旧数据。
7. 当前状态(2026-07-14 实时更新中)
| 节点 | rke2-server | K8s 节点状态 | etcd 成员身份 |
|---|---|---|---|
192.168.122.78 | active (running) | 曾短暂 Ready,目前因 136 加入负载高而 NotReady | voter |
192.168.122.69 | active (running) | 曾短暂 Ready,目前因 136 加入负载高而 NotReady | voter |
192.168.122.136 | activating | NotReady | 尚未加入 etcd member list |
- 78 已完成
cluster-reset,etcd 恢复为单节点集群; - 69 已清理 etcd 数据并成功重新加入,已从 learner 晋升为 voter;
- 136 正在离线导入镜像并尝试加入,需继续观察;
- 由于 etcd 同步与镜像导入负载,三节点当前均显示
NotReady,待 136 完成加入并同步后应恢复正常。
8. 关键文件路径速查
| 路径 | 说明 |
|---|---|
/etc/rancher/rke2/config.yaml | RKE2 配置文件 |
/etc/rancher/rke2/registries.yaml | 镜像仓库配置 |
/var/lib/rancher/rke2/server/db/etcd/config | etcd 静态 Pod 配置(由 RKE2 生成,不建议手动修改) |
/var/lib/rancher/rke2/server/db/etcd/member | etcd 数据目录 |
/var/lib/rancher/rke2/server/db/etcd.bak.* | 备份目录 |
/var/lib/rancher/rke2/server/token | 集群 token 文件 |
/var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst | 离线镜像包 |
/var/lib/rancher/rke2/agent/containerd/.../etcdctl | etcdctl 可执行文件(overlayfs 路径可能变化) |
9. 结论
- 本次继续排查发现原集群并未真正恢复,三节点均处于异常状态;
- 通过 RKE2 的
cluster-reset参数在 78 上重新执行了 etcd 单节点灾难恢复; - 69 已成功清理旧 etcd 数据并重新加入集群,成为正式 voter;
- 136 正在重新加入过程中,需继续等待离线镜像导入与 etcd learner 同步完成;
- 核心教训:
- 应使用
cluster-reset: true而非手动修改 etcd config 的force-new-cluster; - 多 control-plane 节点恢复时应逐台加入,避免 etcd learner 数量超限;
- 离线环境下镜像导入与 learner 同步会显著延长恢复时间,期间需保持耐心并避免频繁重启。
- 应使用