主题
RKE2 新增 master 节点失败:多节点同时加入触发 etcd learner 死锁(too many learner members)
问题现象
已有 1 个 server 节点的 RKE2 集群扩容时,两台新 server 节点同时启动 rke2-server,双双卡在 activating 状态超过 10 分钟,始终无法加入集群。
节点 A(192.168.122.21)日志循环报:
text
Adding member sza122021.local-xxxx=https://192.168.122.21:2380 to etcd cluster [...]
Waiting for other members to finish joining etcd cluster: etcdserver: too many learner members in cluster节点 B(192.168.122.22)日志循环报:
text
Failed to test etcd connection: failed to get etcd status: rpc error: code = Unavailable
desc = connection error: desc = "transport: authentication handshake failed: context deadline exceeded"环境信息
- RKE2 版本:
v1.35.6+rke2r1 - 操作系统:Rocky Linux 9.8 (Blue Onyx)
- 集群形态:3 × server(control-plane + etcd),首节点 192.168.122.20 已正常
- CNI:Calico,kube-proxy IPVS 模式
根因分析
两个问题叠加形成 etcd learner 死锁:
- 两台节点同时启动加入:etcd 集群同一时间只允许存在 1 个 learner(学习成员)。节点 B 先注册为 learner,节点 A 的
member add因此被拒,循环报too many learner members in cluster。 - 节点 B 上的
iptables.service默认 REJECT 规则阻断 etcd 对等端口 2380:Rocky Linux 9 预置的/etc/sysconfig/iptables在INPUT/FORWARD链末尾带有REJECT --reject-with icmp-host-prohibited,导致 leader 无法向 learner(节点 B)同步 raft 数据,learner 永远无法追平日志、无法被提升(promote)为正式成员。
于是:B 永远是 learner → A 永远加不进来 → 死锁。
排查步骤
bash
# 1. 在首节点通过 etcd 容器查看成员列表(重点看 IS LEARNER 列)
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/k3s/containerd/containerd.sock
ETCD_CTR=$(crictl ps --name "^etcd" -q | head -1)
crictl exec $ETCD_CTR 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 \
member list -w table
# 2. 检查新节点防火墙兜底规则(本案例的诱因)
ssh root@<新节点> 'systemctl is-enabled iptables; iptables -L INPUT -n | tail -2; iptables -L FORWARD -n | tail -2'本案例中修复防火墙后再次查看成员列表:节点 B 已被提升为正式成员(IS LEARNER=false),节点 A 从未注册成功(不在成员列表中)。
修复步骤
bash
# 1) 两台新节点:停止服务、清除防火墙 REJECT 规则并禁止其开机恢复
systemctl stop rke2-server
systemctl disable iptables
iptables -D INPUT -j REJECT --reject-with icmp-host-prohibited
iptables -D FORWARD -j REJECT --reject-with icmp-host-prohibited
# 2) 从未成功加入的节点(A):清理残留 etcd 数据
rm -rf /var/lib/rancher/rke2/server/db
# 3) 若集群中残留卡死的 learner 成员(本案例无),在首节点移除:
# crictl exec $ETCD_CTR etcdctl <证书参数...> member remove <成员ID>
# 4) 关键:逐个启动,任何时刻只允许一个新成员加入
systemctl start rke2-server # 先启动节点 B(已是正式成员,直接同步)
kubectl get nodes # 等待节点 B Ready
systemctl start rke2-server # 再启动节点 A(作为唯一 learner 加入)
kubectl get nodes # 等待节点 A Ready验证
- 3 个节点全部
Ready(control-plane,etcd); etcdctl member list:3 个成员全部started、IS LEARNER=false;etcdctl endpoint health --cluster:3 个端点全部true;- 在两个新节点上分别运行测试 Pod,集群 DNS 解析正常,跨节点 CNI 网络正常。
经验教训
- RKE2 多 server 节点扩容必须逐个进行:启动一个,等其
Ready且确认 etcd learner 提升完成(member list中IS LEARNER=false)后,再启动下一个。并发加入必然触发too many learner members。 - learner 卡住时优先查网络:learner 需要通过 2380 端口从 leader 同步数据,任何防火墙拦截都会使其永远无法提升,进而阻塞后续所有节点加入。
- 加入失败需重试时:从未成功加入的节点先清理
/var/lib/rancher/rke2/server/db再启动;已成功注册但数据损坏的节点,则需先在集群侧member remove再清理数据重加。 - Rocky/RHEL 9 部署 RKE2 前必须处理防火墙:即使未安装 firewalld,
iptables.service的默认 REJECT 规则同样会阻断集群端口(etcd 2379/2380、API 6443、supervisor 9345、CNI 等),应提前systemctl disable --now iptables ip6tables。同类问题参见《RKE2 新增 master 节点失败:iptables 防火墙拦截 RKE2/Calico 端口》。