如何故障排除 Amazon EKS 的 DNS 故障?

4 分钟阅读
0

在我的 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)。

    有关更多信息,请参阅为什么我的容器组无法连接到 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 问题

完成下面的步骤:

  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

    要进行调试,请将清单文件中使用的映像更新为另一个映像,例如 Docker 网站上的 busybox 映像。

  2. 验证 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 策略

  3. 要验证您的容器组(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
  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 替换为 kubectl 获取的端点中的某个端点的 IP 地址。

从 CoreDNS 容器组(pod)中获取更多详细日志以进行调试

完成下面的步骤:

  1. 打开 CoreDNS 容器组(pod)的调试日志,然后将日志插件添加到 CoreDNS ConfigMap 中:

    kubectl -n kube-system edit configmap coredns

    **注意:**有关更多信息,请参阅 CoreDNS 网站上的 log plugin

  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 值

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 工具来捕获数据包:

  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. 启动一个容器组(pod)来测试其中的 DNS 服务。以下示例使用 Ubuntu 容器映像:

    kubectl run ubuntu --image=ubuntu sleep 1d
    
    kubectl exec -it ubuntu sh
  7. 使用 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)发送一个查询。

  8. 查看数据包捕获结果。

    如果您监控的 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 官方
AWS 官方已更新 6 个月前