从 Pod(而不是工作器节点)中排查 DNS 解析失败问题

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

先决条件

背景

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

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

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

故障排除清单

若要从 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 反馈社区