DNS 问题排查指南
本文档介绍 DNS 相关的常见问题和错误,以及对应的排查和解决方案。
DNS 问题排查流程
排查流程
当发生 DNS 解析失败时,可按照如下流程进行排查
-
首先,我们可以根据解析失败报错,判断问题类型,判断方法参见
客户端常见报错分类
- 如果是因为网络不连通,参见
问题排查思路
的按解析异常的域名类型排查
- 如果是因为域名解析失败,参见
问题排查思路
的按解析异常出现频次排查
- 如果是因为网络不连通,参见
-
如上述排查未解决问题,请按如下步骤排查
-
检查 Pod 配置的 DNSPolicy 字段,确认是否使用了 CoreDNS,具体参见
Pod DNS 配置检查
- 如果没有使用 CoreDNS,则默认会继承节点 DNS 配置,参见
节点 DNS 问题排查
-
如果使用了 CoreDNS,按如下步骤排查
- 排查 CoreDNS 负载运行情况,参见
CoreDNS pod 运行状态排查
- 排查 CoreDNS 日志,参见
CoreDNS pod 日志排查
- 排查 CoreDNS 负载运行情况,参见
- 如果没有使用 CoreDNS,则默认会继承节点 DNS 配置,参见
- 如果使用的是 NodeLocal DNS,参见
NodeLocal DNS 问题排查
-
- 如以上流程都未解决问题,可提交工单
客户端常见报错分类
分类 | 错误 |
---|---|
网络连通性问题 | network unreachable connection timeout connection reset by peer no route to host |
域名解析失败 | no such host could not resolve host name or service not known NXDOMAIN |
注意:不同的 SKD 有不同的报错,上述报错关键字可能并不全面,可以结合报错信息进行判断。
DNS 问题排查思路
按解析异常的域名类型排查
异常类型 | 解决方案 |
---|---|
集群内外域名都异常 | 容器网络不通 CoreDNS Pod 负载高 节点 Conntrack 表满 IPVS 缺陷导致解析异常 |
仅集群外部域名异常 | 集群外部域名解析异常 |
仅 Headless 类型服务域名异常 | Headless 类型服务域名无法解析 |
按解析异常出现频次排查
出现频次 | 解决方案 |
---|---|
异常仅出现在业务高峰时期 | CoreDNS Pod 负载高 节点 Conntrack 表满 |
异常出现频次高 | IPVS 缺陷导致解析异常 |
异常出现频次低 | A 记录和 AAAA 记录并发解析异常 |
异常仅出现在节点扩缩容或CoreDNS缩容时 | IPVS 缺陷导致解析异常 |
问题排查方法
Pod DNS 配置检查
查看业务 pod 的 dnsPolicy 字段,命令如下:
kubectl -n <ns> get pod <pod-name> -o yaml | grep dnsPolicy
该字段取值如下 :
- "Default": Pod 从运行所在的节点继承名称解析配置,即使用云上 DNS 服务器进行域名解析服务
- "ClusterFirst": 使用 CoreDNS 进行域名解析服务,pod 内 /etc/resolv.conf 中 nameserver 将指向 kube-dns 服务的 ClusterIP
- "ClusterFirstWithHostNet": 对于以 hostNetwork 方式运行的 Pod,应将其 DNS 策略显式设置为 "ClusterFirstWithHostNet"。否则,以 hostNetwork 方式和 "ClusterFirst" 策略运行的 Pod 将会做出回退至 "Default" 策略的行为
- "None": 此设置允许 Pod 忽略 Kubernetes 环境中的 DNS 设置,Pod 会使用其 dnsConfig 字段所提供的 DNS 设置
之后可以进一步进入业务 pod,查看业务 pod 内 dns 配置文件是否符合预期。
首先进入容器:
kubectl -n <ns> exec -it <pod-name> -- bash
如 bash
命令不存在,可尝试 sh
然后查看 dns 配置文件:
cat /etc/resolv.conf
如果 dnsPolicy 字段值为 ClusterFirst 或 ClusterFirstWithHostNet,则 resolv.conf 中 nameserver 应为集群中 kube-dns 的 ClusterIP。
如果 dnsPolicy 字段值为 Default,则 resolv.conf 中 nameserver 应和节点上 /etc/resolv.conf 相同。
如果 dnsPolicy 字段值为 None,则 resolv.conf 中配置应和用户自己再 pod yaml 中 dnsConfig 字段配置相同。
连通性异常排查
首先,我们可以检查 pod 到 CoreDNS 的 ClusterIP 的连通性。
可以通过如下命令进入 pod:
kubectl -n <ns> exec -it <pod-name> -- bash
如 bash
命令不存在,可尝试 sh
如 pod 无法通过 bash 或者 sh 登录,可以先登录节点,然后在节点上执行如下命令拿到 container-id:
docker ps | grep <容器名>
然后执行如下命令拿到 pid:
docker inspect <container-id> | grep -i pid
最后通过如下命令进入 pod 网络命名空间:
nsenter -t <pid> -n bash
注意如容器运行时为 containerd,可将上述 docker
命令换为 crictl
。
先通过如下命令拿到 coredns 的 ClusterIP:
kubectl -n kube-system get svc kube-dns
然后通过如下命令依次测试到 ClusteIP 和 pod-ip 的连通性:
telnet <ClusterIP> 53
telnet <pod-ip> 53
如果发现到 ClusterIP 无法连通,但到 CoreDNS 的 pod ip 可以联通,这说明集群的 Service 连通性存在问题,可以去排查 kube-proxy 等提供 Service 负载均衡相关功能的模块。
如果检测发现 pod 到 CoreDNS pod ip 无法连通,那先确认集群 pod 网络是否联通,如果 pod 网络存在问题,需要先解决该问题,常见的问题包括节点网络不通、安全组配置错误等。
如果集群 pod 网络没有问题,那说明可能是 CoreDNS pod 存在问题。
可以通过如下命令测试解析:
dig <domain> @<ClusterIP>
根据解析结果,参考本文其他部分进行相关排查。
CoreDNS pod 运行状态排查
首先确认 coredns pod 运行状态,可以执行如下命令:
kubectl -n kube-system get pod -o wide | grep coredns
预期所有 pod 都应该处于 Running 状态,有有非 Running 的,可以执行如下命令查看原因:
kubectl -n kube-system describe pod <pod-name>
也可以使用如下命令查看 coredns pod 资源使用情况,看是否资源超限:
kubectl -n kube-system top pod -l k8s-app=kube-dns
如过发现 CoreDNS pod 负载过高,可以增加 CoreDNS 的副本数。
如过 coredns pod 状态正常,则可以进一步排查 coredns pod 的日志。
CoreDNS pod 日志排查
命令如下:
kubectl -n kube-system logs <pod-name>
这里,因为集群中服务通过 ClusterIP 负载均衡到多个 pod,可以抽查 coredns pod 日志。
如果想准确将 dns 请求打到某一个 coredns pod,可以通过 dig 命令指定 dns 服务器来实现,命令如下:
dig baidu.com @<pod-ip>
之后再查看对应 pod-ip 的 coredns pod 日志
coredns 日志示例如下:
[INFO] 192.168.2.90:30639 - 8870 "A IN nfd-master.kube-system.svc.cluster.local. udp 69 false 1232" NOERROR qr,aa,rd 114 0.00010245s
其中的关键字 NOERROR 是表示解析成功返回码,常见的返回码如下:
- NOERROR:解析成功
- NXDOMAIN:域名不存在
- SERVFAIL:从上游 DNS 服务器解析错误等
此外,还需要关注日志中是否存在其他错误,一些常见的错误有:
- 无法连接 API Server,请检查 API Server 的状态
- K8S API 兼容性错误,一般是由于 CoreDNS 和 K8S 版本不兼容,通常需要升级 CoreDNS 或 K8S 版本
域名解析失败排查
场景1:集群内 svc 解析成功,公网域名解析失败。这种情况,一般在 coredns pod 日志中会出现 NXDOMAIN 或 SERVFAIL 等返回码,此时可以联系云上 DNS 团队处理。
场景2:私有域名解析失败。需要确认私有域名是否已注册到云上 DNS 中,如果希望 CoreDNS 完成私有域名解析,需要在 CoreDNS 配置文件中添加私有域名解析服务器相关的配置。
场景3:Headless 类型 svc 无法解析。Headless 类型服务,解析结果会直接返回所有 pod ip,请检查服务对应的 pod 是否处于 Running 状态。
节点 DNS 问题排查
如用户负载 dnsPolicy 为 default 或使用 hostNetwork,则会使用节点 DNS 配置。
可在节点上使用 dig 命令进行复现和排查,示例如下:
dig baidu.com
检查节点内核日志,执行如下命令:
dmesg
检查其中是否有网络相关报错,如:
- queue failue
- conntract full
如节点内核日志未发现异常,因节点上 /etc/resolv.conf 中默认配置使用公有云 DNS 服务器,可进一步联系云上 DNS 团队进行处理。
NodeLocal DNS 问题排查
请先阅读 CCE Node Local DNS 说明 ,了解 NodeLocal DNS 的工作原理。
然后根据文档先检查 NodeLocal DNS 相关配置均已生效,其它各环节问题排查,可参考本文档。
常见 DNS 问题和解决方案
容器网络不通
问题现象:
业务 pod DNS 解析持续失败
问题原因:
业务 pod 到 CoreDNS pod 容器网络不通
解决方案:
排查并确保容器网络的连通性正常,可参见问题排查方法中的 连通性异常排查
集群外部域名解析异常
问题现象:
业务 pod 可以正常解析集群内部域名,但无法解析某些集群外部域名
问题原因:
上游服务器域名解析返回异常
解决方案:
查看 CoreDNS pod 的请求日志,确定错误码,日志示例如下:
[INFO] 192.168.2.90:30639 - 8870 "A x.y.com. udp 69 false 1232" NOERROR qr,aa,rd 114 0.00010245s
如返回码不为 NOERROR,说明上游服务器返回错误,常见错误如下:
- NXDOMAIN:域名不存在
- SERVFAIL:一般是上游服务器故障或无法连接到上游服务器
如确定是上游服务器问题,可提交工单处理
Headless 类型服务域名无法解析
问题现象: Headless 类型 svc 无法解析
问题原因:
Headless 类型服务,解析结果会直接返回所有 pod ip,如业务 pod 是没有处于 Running 状态,则无法解析
解决方案:
请检查并确保服务对应的 pod 处于 Running 状态
CoreDNS Pod 负载高
问题现象: 业务 Pod DNS 请求延迟大、概率失败或持续失败
问题原因:
CoreDNS pod 负载高,处理能力不足,导致请求延迟增加或失败
解决方案:
增加 CoreDNS 副本数,或调大 CoreDNS 资源
节点 Conntrack 表满
问题现象: 业务 Pod DNS 在请求高峰时,出现请求概率失败或持续失败 再节点上运行 dmesg -T,在对应时段的日志中,发现有 conntrack full 关键字的错误
问题原因:
业务高峰时,内核 Conntrack 表打满,导致无法进行新的 TCP 或者 UDP 请求
解决方案:
调大节点上的内核 Conntrack 表限制,可提交工单处理
A 记录和 AAAA 记录并发解析异常
问题现象: 业务 Pod 解析域名概率性失败
问题原因:
并发 A 和 AAAA 的 DNS 请求触发 Linux 内核 Conntrack 模块缺陷,导致 UDP 报文丢失
解决方案:
- 如果容器镜像是以Alpine制作的,建议更换基础镜像
- 考虑采用 NodeLocal DNS 缓存方案,提升 DNS 解析性能,降低 CoreDNS 负载
- CentOS、Ubuntu 等基础镜像,可以通过 options timeout:2 attempts:3 rotate single-request-reopen 等参数优化
IPVS 缺陷导致解析异常
问题现象: 集群节点扩缩容、CoreDNS 缩容时,业务出现概率性解析失败,通常时长在五分钟左右
问题原因:
若集群的 kube-proxy 负载均衡模式为 IPVS,在 CentOS 等内核版本小于 4.19 的节点上,摘除 IPVS UDP 类型后端后,一段时间内若新发起的 UDP 报文源端口冲突,该报文会被丢弃
解决方案:
可以考虑采用 NodeLocal DNS 方案,由于 NodeLocal DNS pod 和 CoreDNS pod 间使用 TCP,可以容忍该 IPVS 缺陷导致的丢包问题