排查来自 Pod 内部的 DNS 解析失败,而不是从工作器节点进行故障排除

本文讨论当你尝试从 Microsoft Azure Kubernetes 服务 (AKS) 群集建立出站连接时,如何排查域名系统 (DNS) 解析失败,这些故障发生在 Pod 内部,而不是从工作器节点发生。

先决条件

背景

对于 DNS 解析,Pod 会将请求发送到命名空间中的 kube-system CoreDNS Pod。

如果 DNS 查询针对的是内部组件(例如服务名称),则 CoreDNS Pod 会自行响应。 但是,如果请求针对外部域,CoreDNS Pod 会将请求发送到上游 DNS 服务器。

DNS 服务器上游基于运行 Pod 的工作器节点的 resolv.conf 文件获取。 根据运行工作器节点的虚拟网络的 DNS 设置更新 resolve.conf 文件 (/run/systemd/resolve/resolve.conf) 。

故障排除清单

若要从 Pod 中排查 DNS 问题,请使用以下部分中的说明。

步骤 1:排查 Pod 中的 DNS 问题

可以使用 kubectl 命令从 Pod 中排查 DNS 问题,如以下步骤所示:

  1. 验证 CoreDNS Pod 是否正在运行:

    kubectl get pods -l k8s-app=kube-dns -n kube-system
    
  2. 检查 CoreDNS Pod 是否被过度使用:

    $ kubectl top pods -n kube-system -l k8s-app=kube-dns
    NAME                      CPU(cores)   MEMORY(bytes)
    coredns-dc97c5f55-424f7   3m           23Mi
    coredns-dc97c5f55-wbh4q   3m           25Mi
    
  3. 验证托管 CoreDNS Pod 的节点是否未过度使用。 此外,获取托管 CoreDNS Pod 的节点:

    kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[*].spec.nodeName}'
    
  4. 检查这些节点的使用情况:

    kubectl top nodes
    
  5. 验证 CoreDNS Pod 的日志:

    kubectl logs -l k8s-app=kube-dns -n kube-system
    

注意

若要查看更多调试信息,请在 CoreDNS 中启用详细日志。 若要在 CoreDNS 中启用详细日志记录,请参阅 对 AKS 中的 CoreDNS 自定义项进行故障排除

步骤 2:创建测试 Pod 以运行命令

如果 DNS 解析失败,请执行以下步骤:

  1. 在与有问题的 Pod 相同的命名空间中运行测试 Pod

  2. 在群集中启动测试 Pod:

    kubectl run -it --rm aks-ssh --namespace <namespace> --image=debian:stable
    

    当测试 Pod 运行时,你将获得对 Pod 的访问权限。

  3. 运行以下命令以安装所需的包:

    apt-get update -y
    apt-get install dnsutils -y
    
  4. 验证 resolv.conf 文件是否具有正确的条目:

    cat /etc/resolv.conf
    search default.svc.cluster.local svc.cluster.local cluster.local 00idcnmrrm4edot5s2or1onxsc.bx.internal.cloudapp.net
    nameserver 10.0.0.10
    options ndots:5
    
  5. host使用 命令确定 DNS 请求是否路由到上游服务器:

    $ host -a microsoft.com
    Trying "microsoft.com.default.svc.cluster.local"
    Trying "microsoft.com.svc.cluster.local"
    Trying "microsoft.com.cluster.local"
    Trying "microsoft.com.00idcnmrrm4edot5s2or1onxsc.bx.internal.cloudapp.net"
    Trying "microsoft.com"
    Trying "microsoft.com"
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62884
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 27, AUTHORITY: 0, ADDITIONAL: 5
    
    ;; QUESTION SECTION:
    ;microsoft.com.                 IN      ANY
    
    ;; ANSWER SECTION:
    microsoft.com.          30      IN      NS      ns1-39.azure-dns.com.
    ...
    ...
    ns4-39.azure-dns.info.  30      IN      A       13.107.206.39
    
    Received 2121 bytes from 10.0.0.10#53 in 232 ms
    
  6. 检查 pod 中的上游 DNS 服务器,以确定 DNS 解析是否正常工作。 例如,对于 Azure DNS,请运行以下 nslookup 命令:

    $ nslookup microsoft.com 168.63.129.16
    Server:         168.63.129.16
    Address:        168.63.129.16#53
    ...
    ...
    Address: 20.81.111.85
    

步骤 3:检查显式指定上游 DNS 服务器时 DNS 请求是否正常工作

如果在显式指定上游 DNS 服务器时来自 Pod 的 DNS 请求正常工作,请验证以下条件:

  1. 检查 CoreDNS 的自定义 ConfigMap:

    kubectl describe cm coredns-custom -n kube-system
    

    如果存在自定义 ConfigMap,请验证配置是否正确。 有关详细信息,请参阅使用Azure Kubernetes 服务自定义 CoreDNS

  2. 检查网络策略是否阻止用户数据报协议 (UDP) 端口 53 到命名空间中 kube-system CoreDNS Pod 的流量。

  3. 检查 CoreDNS Pod 是否位于其他节点池 (系统节点池) 。 如果是,检查 (NSG) 的网络安全组是否与阻止 UDP 端口 53 上的流量的系统节点池相关联。

  4. 检查虚拟网络最近是否已更新,以添加新的 DNS 服务器。

    如果发生虚拟网络更新,检查是否也发生了以下事件之一:

    • 节点已重启。
    • 节点中的网络服务已重启。

    若要使 DNS 设置中的更新生效,必须重启节点上的网络服务和 CoreDNS Pod。 若要重启网络服务或 Pod,请使用以下方法之一:

    • 重启节点。

    • 缩放新节点。 (新节点将具有更新的配置。)

    • 重启节点中的网络服务,然后重启 CoreDNS Pod。 请按照下列步骤操作:

      1. 建立与节点 (SSH) 连接的安全外壳。 有关详细信息,请参阅连接到 Azure Kubernetes 服务 (AKS) 群集节点进行维护或故障排除

      2. 从节点内重启网络服务:

        systemctl restart systemd-networkd
        
      3. 检查设置是否已更新:

        cat /run/systemd/resolve/resolv.conf
        
      4. 重启网络服务后,使用 kubectl 重启 CoreDNS Pod:

        kubectl delete pods -l k8s-app=kube-dns -n kube-system
        
  5. 检查虚拟网络 DNS 设置中是否指定了多个 DNS 服务器。

    如果在 AKS 虚拟网络中指定了多个 DNS 服务器,则会发生以下序列之一:

    • AKS 节点将请求作为序列的一部分发送到上游 DNS 服务器。 在此序列中,请求将发送到虚拟网络中配置的第一个 DNS 服务器, (DNS 服务器是否可以访问并运行) 。 如果无法访问第一个 DNS 服务器且未响应,则请求将发送到下一个 DNS 服务器。

      AKS 节点使用 解析程序 命令将请求发送到 DNS 服务器。 此解析程序的配置文件可以在 AKS 节点的 /run/systemd/resolve/resolve.conf 中找到。

      是否存在多个服务器? 在这种情况下,解析程序库会按列出的顺序查询它们。 (使用的策略是先尝试名称服务器。如果查询超时,请尝试下一个名称服务器,然后继续,直到名称服务器列表用完。然后,查询继续尝试连接到名称服务器,直到达到最大重试次数。)

    • CoreDNS 使用转发插件将请求发送到上游 DNS 服务器。 此插件使用随机算法来选择上游 DNS 服务器。 在此序列中,请求可以转到虚拟网络中提到的任何 DNS 服务器。 例如,你可能会收到以下输出:

      $ kubectl describe cm coredns -n kube-system
      Name:         coredns
      Namespace:    kube-system
      Labels:       addonmanager.kubernetes.io/mode=Reconcile
                    k8s-app=kube-dns
                    kubernetes.io/cluster-service=true
      Annotations:  <none>
      
      Data
      ====
      Corefile:
      ----
      .:53 {
          errors
          ready
          health
          kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
          }
          prometheus :9153
          forward . /etc/resolv.conf                            # Here!
          cache 30
          loop
          reload
          loadbalance
          import custom/*.override
      }
      import custom/*.server
      
      
      BinaryData
      ====
      
      Events:  <none>
      

    在 CoreDNS forward 插件中,policy指定用于选择上游服务器的策略。 下表中定义了这些策略。

    策略名称 说明
    random 实现随机上游选择的策略。 此策略是默认策略。
    round_robin 基于轮循机制排序选择主机的策略。
    sequential 基于顺序排序选择主机的策略。

    如果 AKS 虚拟网络包含多个 DNS 服务器,则来自 AKS 节点的请求可能会转到第一个 DNS 服务器。 但是,来自 Pod 的请求可能会转到第二个 DNS 服务器。

原因:DNS 请求的多个目标

如果指定了两个自定义 DNS 服务器,并且第三个 DNS 服务器指定为 Azure DNS (168.63.129.16) ,则节点将向第一个自定义 DNS 服务器发送请求(如果服务器正在运行且可访问)。 在此设置中,节点可以解析自定义域。 但是,来自 Pod 的某些 DNS 请求可能会定向到 Azure DNS。 这是因为 CoreDNS 可以随机选择上游服务器。 在这种情况下,无法解析自定义域。 因此,DNS 请求失败。

解决方案:从虚拟网络设置中删除 Azure DNS

建议不要在虚拟网络设置中将 Azure DNS 与自定义 DNS 服务器组合使用。 如果要使用自定义 DNS 服务器,请在虚拟网络设置中仅添加自定义 DNS 服务器。 然后,在自定义 DNS 服务器的转发器设置中配置 Azure DNS。

有关详细信息,请参阅 使用自己的 DNS 服务器的名称解析

第三方联系人免责声明

Microsoft 提供第三方联系信息,帮助你查找有关本主题的其他信息。 该联系信息如有更改,恕不另行通知。 Microsoft 不保证第三方联系信息的准确性。

联系我们寻求帮助

如果你有任何疑问或需要帮助,请创建支持请求联系 Azure 社区支持。 还可以向 Azure 反馈社区提交产品反馈。