主题
Rancher 下游集群节点不 Ready:Pod 解析 Rancher 域名超时(.local 搜索域 × libvirt dnsmasq 不应答)
问题现象
Rancher(v2.14.3)provisioning 新建 RKE2 下游集群(2 节点:.31 server / .30 agent):
- server 节点注册命令执行成功,
rke2-server正常运行,但 Rancher UI 两台节点一直不 Ready; - agent 节点
.30看起来"添加失败"——rke2-agent服务根本没被安装; - Rancher 侧 machine 状态卡在:
text
PHASE: Provisioning
Ready=Unknown: Waiting for Cluster control plane to be initialized,
waiting for cluster agent to connect环境信息
- Rancher v2.14.3(local 集群 RKE2 v1.35.6 + ingress-nginx,自签 CA,hostname=
ai-ear.cn) - 下游集群 uat1:RKE2 v1.35.6+rke2r1,Calico,traefik
- 节点均为 KVM 虚拟机(libvirt default 网络
192.168.122.0/24,DNS 为宿主机 dnsmasq192.168.122.1) - 内网解析方案:libvirt dnsmasq 静态记录
ai-ear.cn → .20/.21/.22(见《KVM/libvirt 内网静态 DNS 解析方案》)
根因链(4 环相扣)
kubelet 把节点搜索域追加进 Pod:节点
/etc/resolv.conf由 NetworkManager 生成,含search local(libvirt DHCP 下发的域名)。kubelet 生成 Pod resolv.conf 时会把宿主机搜索域追加到集群域之后,Pod 得到search <ns>.svc.cluster.local svc.cluster.local cluster.local local,且ndots:5。解析顺序撞上
.local:ai-ear.cn只有 2 个点 < ndots(5),resolver 依次尝试ai-ear.cn.<ns>.svc.cluster.local→...svc.cluster.local→...cluster.local(均快速 NXDOMAIN)→ai-ear.cn.local→ 最后才是绝对名ai-ear.cn.。libvirt dnsmasq 对 VM 的
*.local查询不应答:抓包证实查询发出后无任何回包(同一上游的其它查询如NS .秒回;宿主机本机查ai-ear.cn.local返回 SERVFAIL)。.local是 mDNS 保留域,dnsmasq 对该域的处理与宿主机 iptables/libvirt 规则叠加后,来自 VM 网段的.local查询被静默丢弃,CoreDNS forward 只能等 10s+ 超时:text[ERROR] plugin/errors: 2 ai-ear.cn.local. A: read udp 10.22.183.194:46366->192.168.122.1:53: i/o timeout超时毒化整个解析:Go resolver 在
ai-ear.cn.local超时后直接返回i/o timeout,永远走不到绝对名ai-ear.cn.(tcpdump 中从未出现绝对名查询):textcattle-cluster-agent: Failed to dial steve aggregation server: dial tcp: lookup ai-ear.cn: i/o timeoutcluster agent 连不上 Rancher → 控制平面迟迟不"初始化完成" →
.30的 machine plan 不下发 →rke2-agent从未安装(这就是"agent 节点添加失败"的真相——不是注册命令问题)。
排障路径(关键分叉点)
.31的rke2-server正常、集群内组件(calico/coredns/cluster-agent)全 Running → 问题不在 RKE2 本身;- cluster agent 日志给出方向:
lookup ai-ear.cn: i/o timeout(DNS 问题而非网络不通); - CoreDNS 日志显示是
ai-ear.cn.local(带后缀)转发超时,不是ai-ear.cn; - 同一 CoreDNS Pod 内 nslookup 上游正常 → 一度迷惑;tcpdump 定案:
.local查询无回包、其它查询有回包 → 锅在上游 dnsmasq 对该域的区别对待,而不是 Calico/Pod 网络。
修复:固化下游集群 CoreDNS(HelmChartConfig)
不改宿主机 dnsmasq(root-only 且属基础设施),在下游集群用 RKE2 官方支持的 HelmChartConfig 给 rke2-coredns 注入两个额外 zone(chart 的 extraConfig 会渲染到 Corefile 顶部):
bash
kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml apply -f - <<'EOF'
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: rke2-coredns
namespace: kube-system
spec:
valuesContent: |-
extraConfig:
ai-ear.cn: # 集群内直接应答 Rancher 域名,不再依赖上游 dnsmasq
parameters: |
{
template IN A ai-ear.cn {
answer "{{ .Name }} 60 IN A 192.168.122.20"
answer "{{ .Name }} 60 IN A 192.168.122.21"
answer "{{ .Name }} 60 IN A 192.168.122.22"
fallthrough
}
template IN AAAA ai-ear.cn {
rcode NOERROR
}
}
local: # 让 .local 立即 NXDOMAIN,resolver 快速跳到绝对名
parameters: |
{
template IN ANY local {
rcode NXDOMAIN
}
}
EOF
kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml -n kube-system rollout restart deploy/rke2-coredns-rke2-coredns效果:
ai-ear.cn→ 集群内直接应答.20/.21/.22(对 dnsmasq 故障免疫);ai-ear.cn.local→ 立即 NXDOMAIN → resolver 继续尝试绝对名 → 成功。
修复后 1 分钟内:cluster agent 回连成功 → 集群 Ready=true → .30 收到 machine plan → 自动安装 rke2-agent → 两节点全部 Ready,Rancher 两台 machine 转 Running/Available。
坑与经验
- extraConfig 渲染的 YAML 缩进坑:chart 模板把
parameters原样内联进Corefile: |-块标量,续行必须 ≥4 空格缩进,否则helm upgrade直接报YAML parse error ... could not find expected ':'。按上面写法({顶格、后续行 4 空格起、收尾}也带 4 空格)可通过。 - "agent 节点添加失败"可能是假象:下游集群控制平面未初始化时,后续节点永远拿不到 plan,先修第一个 server 节点的 cluster agent 回连。
.local是 mDNS 保留域:libvirt 默认 DHCP 域就是local,它会经 kubelet 渗入所有 Pod 的搜索域。凡上游 DNS 对.local处理异常(丢弃/SERVFAIL 而非快速 NXDOMAIN),都会放大成全集群 DNS 故障。- tcpdump 是 DNS 疑难杂症的终审:`nslookup 正常但应用超时"的假象,往往是查询名不同(带不带搜索后缀)导致路径完全不同。
参考命令
bash
# 定位 Pod DNS 实际行为
kubectl exec <pod> -- cat /etc/resolv.conf
# CoreDNS 转发错误
kubectl -n kube-system logs deploy/rke2-coredns-rke2-coredns --tail=50 --timestamps
# 抓包对比(哪些查询有回包)
tcpdump -nn -i any 'udp port 53 and host 192.168.122.1'