Skip to content

RKE2 三 control-plane 节点全部宕机后的集群灾后恢复记录

记录时间:2026-07-13
涉及集群:RKE2 v1.35.6+rke2r1(Rocky Linux 9.8)
涉及节点:

  • 192.168.122.78szc122078)—— 原首节点 / 恢复后的单节点 etcd
  • 192.168.122.69szc122069)—— 原 control-plane/etcd,恢复中仍异常
  • 192.168.122.136szc122136)—— 新加入/重新加入的 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)
网络 CIDRcluster-cidr: 10.12.0.0/16,service-cidr: 10.13.0.0/16
私有镜像仓库192.168.122.156:30000registries.yaml 中仅配置了该 endpoint,未覆盖 docker.io
本地镜像包/var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst
首节点 serverhttps://192.168.122.78:9345
加入 tokenxxx

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: true

3. 已执行的恢复步骤

3.1 全节点清理残留进程

在三节点上依次执行(确保没有残留的 etcd / kube-apiserver 进程或旧挂载):

bash
rke2-killall.sh

3.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

  1. 在 136 上确认 /etc/rancher/rke2/config.yamlservertoken 正确。
  2. 清理无效参数 disable-scheduler-node-taints
  3. 重启 rke2-server
bash
systemctl restart rke2-server
  1. 离线环境首次启动需要导入本地镜像包(约 7–10 分钟),观察日志:
bash
journalctl -u rke2-server -f
  1. 镜像导入完成后,136 成功加入并变为 Ready

4. 当前状态(截至 2026-07-13)

4.1 节点状态

  • 192.168.122.78Ready,单节点 etcd 已恢复,K8s API 可用。
  • 192.168.122.136Ready,已成功重新加入集群。
  • 192.168.122.69rke2-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 refused

4.4 根本原因推测

  • 69 上的 etcd 已经以旧 member ID69eda8d743dc6cf3)启动,并被 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 componentstatus

5.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 100

5.3 推荐修复方案 A:清理 69 的 etcd 数据后重新加入

如果 69 持续无法完成 raft publish 或证书/成员身份冲突,最稳妥的方式是:

  1. 在 78 上确认 69 的成员 ID 并移除(如尚未移除):
bash
etcdctl --cacert ... --cert ... --key ... --endpoints https://127.0.0.1:2379 member remove 69eda8d743dc6cf3
  1. 在 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)
  1. 确认 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
  1. 启动服务:
bash
systemctl start rke2-server
journalctl -u rke2-server -f
  1. 等待本地镜像导入完成(离线环境约 7–10 分钟),然后确认:
bash
kubectl get nodes -o wide
kubectl get componentstatus
etcdctl ... member list -w table

5.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. 已知注意事项

  1. 离线镜像拉取会超时:RKE2 启动时仍会尝试从 docker.io 拉取 rke2-images-all.linux-amd64.txt 中缺失的镜像,失败后才会使用本地 tar 包。不影响最终启动,但会延长启动时间。后续建议将缺失镜像推送到私有仓库并在 registries.yaml 中配置 docker.io mirror。

  2. force-new-cluster 是破坏性操作:仅在全部 etcd 节点都不可用、且无其他备份时使用。恢复完成后一定要记得从 etcd/config 中移除该参数并重启。

  3. 清理 etcd 数据前必须备份:删除 /var/lib/rancher/rke2/server/db/etcd 会导致该节点丢失本地 etcd 成员信息,重新加入时会生成新的 member ID。

  4. 恢复期间尽量减少对集群的写操作:在 69 未完全恢复前,避免大量 Pod 调度或资源创建,以防再次触发 quorum 相关异常。


7. 关键文件路径速查

路径说明
/etc/rancher/rke2/config.yamlRKE2 配置文件
/etc/rancher/rke2/registries.yaml镜像仓库配置
/var/lib/rancher/rke2/server/db/etcd/configetcd 静态 Pod 配置
/var/lib/rancher/rke2/server/db/etcd/memberetcd 数据目录
/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/.../etcdctletcdctl 可执行文件(overlayfs 路径可能变化)

6. 继续排查与修复(2026-07-14)

6.1 实际状态与文档记录的差异

2026-07-14 继续排查时发现,文档中“78 Ready / 136 Ready / 69 仍在 activating”的状态已不复存在,三节点实际均为异常:

节点实际状态
192.168.122.78rke2-server 处于 activating 并反复 crashloop,报错 failed to reconcile with local datastore: context deadline exceeded
192.168.122.69rke2-server 处于 activating,尝试加入集群
192.168.122.136rke2-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 并创建新的单节点集群。步骤如下:

  1. 三节点全部停止并清理残留进程
bash
systemctl stop rke2-server
rke2-killall.sh
  1. 在 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 会再次启动它。

  1. 重置完成后移除该参数并再次启动
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 关键注意事项

  1. 不要同时启动多个待加入的 control-plane 节点:etcd 单 learner 限制会导致加入失败并拖垮现有 etcd。
  2. cluster-reset 会重置 token/证书:虽然本例中重置后 token 与之前相同,但理论上应重新从 78 的 /var/lib/rancher/rke2/server/token 获取最新 token。
  3. 离线镜像导入耗时较长:RKE2 会依次尝试从 docker.io 拉取每个镜像并超时,然后才使用本地 tar 包。整个过程在虚拟机/慢磁盘上可能超过 10 分钟。
  4. learner 同步期间节点状态可能全部 NotReady:这是 etcd 高负载导致的临时现象,不要急于重启服务,避免进一步扰乱 raft 状态。
  5. 清理 etcd 数据前务必备份:本例中已使用 mv ... etcd.bak.<时间戳> 保留旧数据。

7. 当前状态(2026-07-14 实时更新中)

节点rke2-serverK8s 节点状态etcd 成员身份
192.168.122.78active (running)曾短暂 Ready,目前因 136 加入负载高而 NotReadyvoter
192.168.122.69active (running)曾短暂 Ready,目前因 136 加入负载高而 NotReadyvoter
192.168.122.136activatingNotReady尚未加入 etcd member list
  • 78 已完成 cluster-reset,etcd 恢复为单节点集群;
  • 69 已清理 etcd 数据并成功重新加入,已从 learner 晋升为 voter;
  • 136 正在离线导入镜像并尝试加入,需继续观察;
  • 由于 etcd 同步与镜像导入负载,三节点当前均显示 NotReady,待 136 完成加入并同步后应恢复正常。

8. 关键文件路径速查

路径说明
/etc/rancher/rke2/config.yamlRKE2 配置文件
/etc/rancher/rke2/registries.yaml镜像仓库配置
/var/lib/rancher/rke2/server/db/etcd/configetcd 静态 Pod 配置(由 RKE2 生成,不建议手动修改)
/var/lib/rancher/rke2/server/db/etcd/memberetcd 数据目录
/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/.../etcdctletcdctl 可执行文件(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 同步会显著延长恢复时间,期间需保持耐心并避免频繁重启。