4、网络层面排查(一):节点DNS解析失败导致无法解析仓库域名

镜像拉取的第一步是域名解析。Kubelet 或容器运行时(如 containerd)在拉取镜像前,会先向 DNS 服务器查询仓库域名(如 registry.k8s.io、docker.io)对应的 IP 地址。如果节点 DNS 配置错误或上游 DNS 不可达,解析就会失败,直接导致 ErrImagePull 或 ImagePullBackOff。

典型现象:执行 kubectl describe pod 看到事件 Failed to pull image "xxx": rpc error: code = Unknown desc = failed to resolve reference "xxx": failed to do request: Head "https://xxx": dial tcp: lookup xxx on 10.96.0.10:53: no such host。关键线索是 "no such host" 或 "server misbehaving"。

4.1 DNS 解析链路与关键组件

K8s 节点上的 DNS 解析涉及三层组件,任何一层出问题都会导致解析失败:

层级 组件 常见故障点
1 系统 DNS 解析器(glibc / musl) /etc/resolv.conf 配置错误、search 域过长、ndots 值不合理
2 节点本地 DNS 服务(systemd-resolved / dnsmasq / NodeLocal DNSCache) 服务未运行、缓存污染、上游转发超时
3 上游 DNS 服务器(CoreDNS / 云厂商 DNS / 自建 DNS) CoreDNS Pod 异常、防火墙拦截 UDP 53、上游递归超时
排查口诀:先测节点本地,再测集群 DNS,最后测公网递归。逐层缩小范围,不要跳过基础检查。

4.2 节点本地 DNS 解析排查步骤

以下步骤在故障节点上以 root 或 sudo 权限执行:

  1. 检查 /etc/resolv.conf 内容
    cat /etc/resolv.conf
    # 期望输出示例:
    # nameserver 10.96.0.10
    # nameserver 192.168.1.1
    # search default.svc.cluster.local svc.cluster.local cluster.local
    # options ndots:5

    常见问题:nameserver 指向了已删除的 CoreDNS Service IP、search 域超过 6 个导致解析延迟、ndots 值过大导致不必要的 DNS 查询。

  2. 使用 nslookup 或 dig 测试域名解析
    # 测试公网仓库域名
    nslookup registry.k8s.io
    # 测试集群内部域名
    nslookup kubernetes.default.svc.cluster.local
    
    # 使用 dig 查看详细响应
    dig @10.96.0.10 registry.k8s.io +short

    如果 nslookup 返回 server can't find xxx: NXDOMAIN 或 connection timed out,说明 DNS 解析异常。

  3. 检查 DNS 服务端口连通性
    # 测试 UDP 53 端口
    nc -vuz 10.96.0.10 53
    # 测试 TCP 53 端口(大响应时使用)
    nc -vz 10.96.0.10 53

    如果端口不通,检查节点防火墙规则(iptables / nftables)或安全组是否放行了 DNS 流量。

  4. 检查 systemd-resolved 状态(如果启用)
    systemctl status systemd-resolved
    resolvectl status
    resolvectl query registry.k8s.io

    如果 systemd-resolved 未运行或配置了错误的 DNS 服务器,会导致解析失败。

4.3 DNS 解析失败故障树(SVG)

下图展示了从 Pod 发起镜像拉取到 DNS 解析失败的全链路排查路径:

DNS 解析失败故障树 镜像拉取失败:DNS 解析错误 节点本地 DNS 配置错误 CoreDNS 服务异常 上游 DNS 不可达 /etc/resolv.conf 配置错误 systemd-resolved 未运行 防火墙拦截 UDP 53 CoreDNS Pod 未运行 CoreDNS 配置错误 CoreDNS 上游转发超时 云厂商 DNS 服务故障 公网 DNS 递归超时 DNS 缓存污染 排查顺序:节点本地 → CoreDNS → 上游 DNS 使用 nslookup/dig 逐层测试,定位故障层级

4.4 常见 DNS 配置错误与修复

错误类型 现象 修复方法
/etc/resolv.conf 中 nameserver 指向已删除的 Service IP nslookup 超时,connection timed out 更新 nameserver 为正确的 CoreDNS ClusterIP 或节点 DNS
search 域超过 6 个 DNS 查询延迟高,部分域名解析失败 减少 search 域数量,或调整 ndots:3
systemd-resolved 占用 53 端口但未转发 本地进程无法解析,resolvectl 显示错误 重启 systemd-resolved 或配置 DNSStubListener=no
节点防火墙未放行 UDP 53 nc 测试端口不通,nslookup 超时 添加 iptables 规则:-A OUTPUT -p udp --dport 53 -j ACCEPT
CoreDNS 上游 forward 配置错误 集群内部域名正常,外部域名解析失败 检查 CoreDNS ConfigMap 中的 forward 指令

4.5 快速验证脚本

将以下脚本保存为 dns_check.sh,在故障节点上执行,可快速输出 DNS 健康状态:

#!/bin/bash
# K8s 节点 DNS 健康检查脚本
echo "=== /etc/resolv.conf ==="
cat /etc/resolv.conf

echo ""
echo "=== 测试公网仓库域名 ==="
for domain in registry.k8s.io docker.io quay.io; do
  result=$(nslookup "$domain" 2>&1)
  if echo "$result" | grep -q "NXDOMAIN\|server can't find\|connection timed out"; then
    echo "[FAIL] $domain - 解析失败"
  else
    echo "[OK]   $domain - 解析成功"
  fi
done

echo ""
echo "=== 测试集群内部域名 ==="
for domain in kubernetes.default.svc.cluster.local; do
  result=$(nslookup "$domain" 2>&1)
  if echo "$result" | grep -q "NXDOMAIN\|server can't find\|connection timed out"; then
    echo "[FAIL] $domain - 解析失败"
  else
    echo "[OK]   $domain - 解析成功"
  fi
done

echo ""
echo "=== DNS 端口连通性测试 ==="
for ns in $(awk '/^nameserver/{print $2}' /etc/resolv.conf); do
  if nc -vuz "$ns" 53 2>&1 | grep -q "succeeded"; then
    echo "[OK]   $ns:53 - UDP 可达"
  else
    echo "[FAIL] $ns:53 - UDP 不可达"
  fi
done
最佳实践:建议在集群中部署 NodeLocal DNSCache(kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns.yaml),将 DNS 缓存放在节点本地,减少对 CoreDNS 的压力,同时提高解析稳定性。