如何故障排除 Amazon EKS 的 DNS 故障?
在我的 Amazon Elastic Kubernetes Service(Amazon EKS)集群中使用 CoreDNS 的应用程序或容器组(pod)无法进行内部或外部 DNS 名称解析。
简述
在 Amazon EKS 集群内运行的容器组(pod)使用 CoreDNS 集群 IP 地址作为名称服务器来查询内部和外部 DNS 记录。如果 CoreDNS 容器组(pod)、服务配置或连接出现问题,则应用程序可能会无法获得 DNS 解析。
一个名为 kube-dns 的服务对象对应代表了 CoreDNS 容器组(pod)。要解决 CoreDNS 容器组(pod)的问题,请验证 kube-dns 服务所有组件的工作状态,例如服务端点选项和 iptables 规则。
解决方案
以下解决方案适用于 CoreDNS ClusterIP 10.100.0.10。
完成下面的步骤:
-
获取您的 CoreDNS 服务的 ClusterIP:
kubectl get service kube-dns -n kube-system
-
验证 DNS 端点是否已公开并指向 CoreDNS 容器组(pod):
kubectl -n kube-system get endpoints kube-dns
输出示例:
NAME ENDPOINTS AGE kube-dns 192.168.2.218:53,192.168.3.117:53,192.168.2.218:53 + 1 more... 90d
**注意:**如果端点列表为空,则检查 CoreDNS 容器组(pod)的容器组(pod)状态。
-
验证安全组或网络访问控制列表(网络 ACL)与 CoreDNS 通信时没有阻止容器组(pod)。
有关更多信息,请参阅为什么我的容器组无法连接到 Amazon EKS 中的其他容器组?
验证 kube-proxy 容器组(pod)是否正在运行
要验证 kube-proxy 容器组(pod)是否可以访问集群的 API 服务器,请检查控制面板的日志中是否存在超时错误。此外,请检查是否存在 403 未经授权错误。
获取 kube-proxy 日志:
kubectl logs -n kube-system --selector 'k8s-app=kube-proxy'
**注意:**kube-proxy 从控制面板获取端点并在每个节点上创建 iptables 规则。
检查问题发生时 CoreDNS 容器组(pod)的 CPU 利用率
Amazon EKS CoreDNS 插件仅为 CoreDNS 容器组(pod)的内存添加了 170Mi 的限制。CoreDNS 容器组(pod)没有定义 CPU 限制,因此容器可以使用其运行的节点上的所有可用 CPU 资源。如果节点 CPU 利用率达到 100%,那么您的 Amazon EKS 应用程序日志中可能会出现 DNS 超时错误。这是因为 CoreDNS 容器组(pod)没有足够的 CPU 资源来处理所有 DNS 查询。
连接到应用程序容器组(pod)以解决 DNS 问题
完成下面的步骤:
-
要在应用程序容器组(pod)中运行命令,请运行以下命令来访问正在运行的容器组(pod)中的 Shell:
$ kubectl exec -it your-pod-name -- sh
如果应用程序容器组(pod)没有可用的 Shell 执行文件,则会收到与以下示例类似的错误:
"OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown command terminated with exit code 126
要进行调试,请将清单文件中使用的映像更新为另一个映像,例如 Docker 网站上的 busybox 映像。
-
验证 kube-dns 服务的集群 IP 地址是否在您的容器组(pod)的 /etc/resolv.conf 文件中。在容器组(pod)内的 Shell 中运行以下命令:
cat /etc/resolv.conf
以下示例 resolv.conf 文件显示了一个容器组(pod),该容器组(pod)配置为将 DNS 请求指向 10.100.0.10。IP 地址必须与您的 kube-dns 服务的 ClusterIP 相匹配:
nameserver 10.100.0.10 search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal options ndots:5
**注意:**您可以使用容器组(pod)规范中的 dnsPolicy 字段来管理容器组(pod)的 DNS 配置。如果您不填充此字段,则默认使用 ClusterFirst DNS 策略。有关 ClusterFirst DNS 策略的更多信息,请参阅 Kubernetes 网站上的 Pod 的 DNS 策略。
-
要验证您的容器组(pod)是否可以使用默认 ClusterIP 来解析内部域名,请在该容器组(pod)内部的 Shell 中运行以下命令:
nslookup kubernetes.default 10.100.0.10
输出示例:
Server: 10.100.0.10 Address: 10.100.0.10#53 Name: kubernetes.default.svc.cluster.local Address: 10.100.0.1
-
要验证您的容器组(pod)是否可以使用默认 ClusterIP 来解析外部域名,请在该容器组(pod)内部的 Shell 中运行以下命令:
nslookup amazon.com 10.100.0.10
输出示例:
Server: 10.100.0.10 Address: 10.100.0.10#53 Non-authoritative answer: Name: amazon.com Address: 176.32.98.166 Name: amazon.com Address: 205.251.242.103 Name: amazon.com Address: 176.32.103.205
-
验证您的容器组(pod)是否可以直接使用 CoreDNS 容器组(pod)IP 地址进行解析。在容器组(pod)内的 Shell 中运行以下命令:
nslookup kubernetes COREDNS_POD_IP nslookup amazon.com COREDNS_POD_IP
**注意:**将 COREDNS_POD_IP 替换为 kubectl 获取的端点中的某个端点的 IP 地址。
从 CoreDNS 容器组(pod)中获取更多详细日志以进行调试
完成下面的步骤:
-
打开 CoreDNS 容器组(pod)的调试日志,然后将日志插件添加到 CoreDNS ConfigMap 中:
kubectl -n kube-system edit configmap coredns
**注意:**有关更多信息,请参阅 CoreDNS 网站上的 log plugin。
-
在输出中显示的编辑器界面中,添加日志字符串:
kind: ConfigMap apiVersion: v1 data: Corefile: | .:53 { log # Enabling CoreDNS Logging errors health kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure upstream fallthrough in-addr.arpa ip6.arpa } ... ...
**注意:**重新加载配置 CoreDNS 需要几分钟才能完成。要立即应用更改,请逐个重启容器组(pod)。
-
检查 CoreDNS 日志,查看应用程序容器组(pod)的解析请求是否有失败或成功记录:
kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'
更新 ndots 值
ndots 值是在初始绝对查询之前解析查询时,域名中必须出现的点的数量。
例如,在未完全限定的域名中,将 ndots 选项设置为默认值 5。然后,所有不在内部域 cluster.local 的外部域名,在查询之前都会附加到搜索域。
以下示例包含应用程序容器组(pod)的 /etc/resolv.conf 文件设置:
nameserver 10.100.0.10 search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal options ndots:5
CoreDNS 在查询的域名中查看是否有五个点。如果容器组(pod)调用 amazon.com 的 DNS 解析请求,则您的日志中将显示与以下示例类似的内容:
[INFO] 192.168.3.71:33238 - 36534 "A IN amazon.com.default.svc.cluster.local. udp 54 false 512" NXDOMAIN qr,aa,rd 147 0.000473434s [INFO] 192.168.3.71:57098 - 43241 "A IN amazon.com.svc.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000066171s [INFO] 192.168.3.71:51937 - 15588 "A IN amazon.com.cluster.local. udp 42 false 512" NXDOMAIN qr,aa,rd 135 0.000137489s [INFO] 192.168.3.71:52618 - 14916 "A IN amazon.com.ec2.internal. udp 41 false 512" NXDOMAIN qr,rd,ra 41 0.001248388s [INFO] 192.168.3.71:51298 - 65181 "A IN amazon.com. udp 28 false 512" NOERROR qr,rd,ra 106 0.001711104s
**注意:**NXDOMAIN 表示未找到域名记录,而 NOERROR 表示已找到域名记录。
每个搜索域名都会附加到 amazon.com,然后才对合成后的绝对域名进行解析调用。末尾添加点号(.)的最终域名是一个完全限定的域名。因此,对于每个外部域名查询,可能会有四到五个额外的调用,使 CoreDNS 容器组(pod)不堪重负。
要解决此问题,请将 ndots 更改为 1,以使系统仅查找一个点号。或者,在您查询或使用的域名的末尾添加一个点号(.):
nslookup example.com.
考虑 VPC 解析器(AmazonProvidedDNS)限制
Amazon Virtual Private Cloud(Amazon VPC)解析器有一个最大硬限制,每个网络接口每秒仅可接收 1024 个数据包。如果多个 CoreDNS 容器组(pod)位于同一个节点上,则外部域名查询就更有可能达到此限制。
要使用 PodAntiAffinity 规则在不同的实例上调度 CoreDNS 容器组(pod),请在 CoreDNS 部署中添加以下选项:
podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: k8s-app operator: In values: - kube-dns topologyKey: kubernetes.io/hostname weight: 100
**注意:**有关 PodAntiAffinity 的更多信息,请参阅 Kubernetes 网站上的 Pod 间的亲和性和反亲和性。
使用 tcpdump 捕获来自 Amazon EKS Worker 节点的 CoreDNS 数据包
为了帮助您诊断 DNS 解析问题,请使用 tcpdump 工具来捕获数据包:
-
找到运行 CoreDNS 容器组(pod)的 Worker 节点:
kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide
-
使用 SSH 连接到运行 CoreDNS 容器组(pod)的 Worker 节点,然后安装 tcpdump 工具:
sudo yum install tcpdump –y
-
在 Worker 节点上找到 CoreDNS 容器组(pod)进程 ID:
ps ax | grep coredns
-
在 Worker 节点上,在 CoreDNS 容器组(pod)网络上捕获数据包,以监控 UDP 端口 53 上的网络流量:
sudo nsenter -n -t PID tcpdump udp port 53
-
从另一个终端获取 CoreDNS 服务和容器组(pod)IP 地址:
kubectl describe svc kube-dns -n kube-system
注意:记下位于 IP 字段中的服务 IP 地址和位于端点字段中的容器组(pod)IP 地址。
-
启动一个容器组(pod)来测试其中的 DNS 服务。以下示例使用 Ubuntu 容器映像:
kubectl run ubuntu --image=ubuntu sleep 1d kubectl exec -it ubuntu sh
-
使用 nslookup 工具对域名执行 DNS 查询,例如 amazon.com:
nslookup amazon.com
对 CoreDNS 服务 IP 地址明确执行相同的查询:
nslookup amazon.com COREDNS_SERVICE_IP
对每个 CoreDNS 容器组(pod)的 IP 地址执行查询:
nslookup amazon.com COREDNS\_POD\_IP
**注意:**如果您正在运行多个 CoreDNS 容器组(pod),请执行多个查询,以便至少向您从中捕获流量的容器组(pod)发送一个查询。
-
查看数据包捕获结果。
如果您监控的 CoreDNS 容器组(pod)遇到 DNS 查询超时问题,并且您在数据包捕获中看不到相关查询,请检查您的网络连接。确保检查 Worker 节点之间的网络连通正常。
如果您看到针对没有捕获数据包的容器组(pod)IP 地址的 DNS 查询超时,则在相关 Worker 节点上执行另一次数据包捕获操作。
要保存数据包捕获的结果,请在 tcpdump 命令中添加 -w FILE_NAME 标志。以下示例将结果写入名为 capture.pcap 的文件中:
tcpdump -w capture.pcap udp port 53
相关信息
用于 Kubernetes 集群 DNS 的 CoreDNS GA 正式发布
这篇文章位于 Kubernetes 网站。
相关内容
- AWS 官方已更新 1 年前
- AWS 官方已更新 7 个月前
- AWS 官方已更新 3 年前