如何使用 Amazon EKS 排查 DNS 故障?
上次更新时间:2020 年 2 月 21 日
我的 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。
1.要获取您的 CoreDNS 服务的 ClusterIP,运行以下命令:
kubectl get service kube-dns -n kube-system
2.要验证 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 状态。
3.验证 pod 在与 CoreDNS 通信时不会被安全组或网络访问控制列表(网络 ACL)阻止。
如需更多信息,见为什么我的 pod 不会连接到 Amazon EKS 中的其他 pod?
验证 kube-proxy pod 正常运行
要验证 kube-proxy pod 具有 EKS 集群的 API 服务器访问权限,您可以检查您的控制层面超时错误日志或 403 未授权错误日志。
要获取 kube-proxy 日志,运行以下命令:
kubectl logs -n kube-system --selector 'k8s-app=kube-proxy'
注意:kube-proxy 从控制层面获取终端节点,并且在每个工作线程节点上创建 iptables 规则。
连接至应用程序 pod 以排查 DNS 问题
1.要在您的应用程序 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
要进行调试,您可以将您的清单文件中所使用的映像更新为其他映像(如 busybox 映像)。
2.要验证 kube-dns 服务的集群 IP 位于您的 pod 的 /etc/resolv.conf 中,在 pod 内的 shell 中运行以下命令:
cat /etc/resolv.conf
以下示例 resolv.conf 显示的是为 DNS 请求被配置指向 10.100.0.10 的 pod。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 策略。
3.要验证您的 pod 可以使用默认的 clusterIP 解析内部域,在 pod 内的 shell 中运行以下命令:
nslookup kubernetes 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
4.要验证您的 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
5.要验证您的 pod 可以直接使用 CoreDNS pod 的 IP 地址进行解析,在 pod 内的 shell 中运行以下命令。
nslookup kubernetes COREDNS_POD_IP
nslookup amazon.com COREDNS_POD_IP
注意:将 COREDNS_POD_IP 替换为终端节点 IP,而且此类终端节点 IP 是您之前使用的 kubectl 获取的终端节点之一。
从 coreDNS pod 获取更多详细日志以进行调试
1.要启用 CoreDNS pod 的调试日志,并添加日志插件至 CoreDNS ConfigMap,运行以下命令:
kubectl -n kube-system edit configmap coredns
2.在输出的编辑器屏幕中,添加日志字符串。见以下示例:
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,以立即应用更改。
3.要检查 CoreDNS 日志是否失败,或获得来自应用程序 pod 的任何命中,运行以下命令:
kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'
搜索与 ndots 组合
DNS 将 nameserver 用于名称解析(通常为 kube-dns 服务的集群 IP)。DNS 使用搜索补充查询名称,使其成为完全限定域名。包含在域中搜索 workerNode。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 解析调用,您的日志将类似于以下内容:
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
192.168.3.71:57098 - 43241 "A IN amazon.com.svc.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000066171s
192.168.3.71:51937 - 15588 "A IN amazon.com.cluster.local. udp 42 false 512" NXDOMAIN qr,aa,rd 135 0.000137489s
192.168.3.71:52618 - 14916 "A IN amazon.com.ec2.internal. udp 41 false 512" NXDOMAIN qr,rd,ra 41 0.001248388s
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 不堪重负。
要解决此问题,可将 ndots 更改为 1(仅查找一个点)或在被查询或使用的域后附加一个点 ( . )。
nslookup example.com.
注意 VPC 解析器 (AmazonProvidedDNS) 的限制
VPC 解析器仅可接受在每个网络接口上每秒发送 1024 个数据包的最大硬限制。如果相同工作线程节点上有多个 CoreDNS pod,则外部域查询达到此限制的几率更大。
要在独立实例上使用 PodAntiAffinity 规则来安排 CoreDNS pod,添加以下选项至 CoreDNS 部署:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
topologyKey: kubernetes.io/hostname