如何使用 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 使用搜索补充查询名称,使其成为完全限定域名。包含在域中搜索 workerNodendots 的值为在初次绝对查询前名称中必须出现的用于解析查询的点数。

例如,您可以在未完全限定的域名中将 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 不堪重负。

要解决此问题,可将 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

这篇文章对您有帮助吗?

我们可以改进什么?


需要更多帮助?