Skip to content

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 为宿主机 dnsmasq 192.168.122.1
  • 内网解析方案:libvirt dnsmasq 静态记录 ai-ear.cn → .20/.21/.22(见《KVM/libvirt 内网静态 DNS 解析方案》)

根因链(4 环相扣)

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

  2. 解析顺序撞上 .localai-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.

  3. 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
  4. 超时毒化整个解析:Go resolver 在 ai-ear.cn.local 超时后直接返回 i/o timeout永远走不到绝对名 ai-ear.cn.(tcpdump 中从未出现绝对名查询):

    text
    cattle-cluster-agent: Failed to dial steve aggregation server:
    dial tcp: lookup ai-ear.cn: i/o timeout

    cluster agent 连不上 Rancher → 控制平面迟迟不"初始化完成" → .30 的 machine plan 不下发 → rke2-agent 从未安装(这就是"agent 节点添加失败"的真相——不是注册命令问题)。

排障路径(关键分叉点)

  • .31rke2-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。

坑与经验

  1. extraConfig 渲染的 YAML 缩进坑:chart 模板把 parameters 原样内联进 Corefile: |- 块标量,续行必须 ≥4 空格缩进,否则 helm upgrade 直接报 YAML parse error ... could not find expected ':'。按上面写法({ 顶格、后续行 4 空格起、收尾 } 也带 4 空格)可通过。
  2. "agent 节点添加失败"可能是假象:下游集群控制平面未初始化时,后续节点永远拿不到 plan,先修第一个 server 节点的 cluster agent 回连。
  3. .local 是 mDNS 保留域:libvirt 默认 DHCP 域就是 local,它会经 kubelet 渗入所有 Pod 的搜索域。凡上游 DNS 对 .local 处理异常(丢弃/SERVFAIL 而非快速 NXDOMAIN),都会放大成全集群 DNS 故障。
  4. 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'