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 权限执行:
- 检查
/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 查询。
- 使用
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 解析异常。 - 检查 DNS 服务端口连通性
# 测试 UDP 53 端口 nc -vuz 10.96.0.10 53 # 测试 TCP 53 端口(大响应时使用) nc -vz 10.96.0.10 53如果端口不通,检查节点防火墙规则(iptables / nftables)或安全组是否放行了 DNS 流量。
- 检查 systemd-resolved 状态(如果启用)
systemctl status systemd-resolved resolvectl status resolvectl query registry.k8s.io如果 systemd-resolved 未运行或配置了错误的 DNS 服务器,会导致解析失败。
4.3 DNS 解析失败故障树(SVG)
下图展示了从 Pod 发起镜像拉取到 DNS 解析失败的全链路排查路径:
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 的压力,同时提高解析稳定性。