如何使用 Amazon EKS 排查 DNS 故障?

上次更新日期:2021 年 11 月 9 日

我的 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.    验证安全组或网络访问控制列表(网络 ACL)在与 CoreDNS 通信时不会阻止 pod。

如需更多信息,见为什么我的一组容器 (pod) 不会连接到 Amazon EKS 中的其他一组容器 (pod)?

验证 kube-proxy 一组容器 (pod) 正常运行

检查您的控制面板超时错误日志,以验证 kube-proxy 一组容器 (pod) 具有集群的 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 镜像(来自 Docker 网站)。

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 服务的 ClusterIP。DNS 使用搜索补充查询名称,使其成为完全限定域名。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(来自 Kubernetes 网站)规则来安排 CoreDNS pod,添加以下选项至 CoreDNS 部署:

podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - podAffinityTerm:
      labelSelector:
        matchExpressions:
        - key: k8s-app
          operator: In
          values:
          - kube-dns
      topologyKey: kubernetes.io/hostname
    weight: 100

使用 tcpdump 捕获来自 Amazon EKS Worker 节点的 CoreDNS 包

使用 tcpdump 工具执行包捕获,以帮助诊断 DNS 解析问题。此工具有助于验证 DNS 请求的网络流量是否会到达您的 CoreDNS pod 以及是否存在潜在的网络连接问题。要使用 tcpdump,请完成以下步骤。

1.    查找正在运行 CoreDNS pod 的 Worker 节点:

kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide

2.    使用 SSH 连接到正在运行 CoreDNS pod 的 Worker 节点,然后安装 tcpdump 工具:

sudo yum install tcpdump –y

3.    查找 Worker 节点上的 CoreDNS pod 进程 ID:

ps ax | grep coredns

4.    在 Worker 节点上,对 CoreDNS pod 网络执行包捕获操作,以监控 UDP 端口 53 的网络流量:

sudo nsenter -n -t PID tcpdump udp port 53

5.    从单独的终端获取 CoreDNS 服务和 pod IP:

kubectl describe svc kube-dns -n kube-system

注意:请记下在“IP”字段中找到的服务 IP 以及在“端点”字段中找到的 pod IP。

6.    启动一个您将从中测试 DNS 服务的 pod。以下示例使用 Ubuntu 容器镜像:

kubectl run ubuntu --image=ubuntu sleep 1d

kubectl exec -it ubuntu sh

7.    使用 nslookup 工具对域执行 DNS 查询,例如 amazon.com

nslookup amazon.com

对步骤 5 中的 CoreDNS 服务 IP 显式执行相同查询:

nslookup amazon.com COREDNS_SERVICE_IP

对步骤 5 中的每个 CoreDNS pod IP 执行查询:

nslookup amazon.com COREDNS_POD_IP

注意:如果您正运行多个 CoreDNS pod,请执行多个查询,以便使得至少有一个查询发送至从中捕获流量的 pod。

8.    检查包捕获结果。

如果您遇到监控的 CoreDNS pod 出现 DNS 查询超时并且没有看到包捕获中的查询,则您可能存在网络连接问题。请务必检查 Worker 节点之间的网络可达性。

如果您在未捕获的 pod IP 上观察到 DNS 超时,请按照步骤 2-4 在相关 Worker 节点上执行另一次包捕获。

要保存包捕获的结果以供后续参考,请在 tcpdump 命令中添加 -w FILE_NAME 标志。以下示例将结果写入到名为 capture.pcap 的文件:

tcpdump -w capture.pcap udp port 53

这篇文章对您有帮助吗?


您是否需要账单或技术支持?