本页介绍了如何解决 Google Kubernetes Engine (GKE) 中的 kube-dns 问题。
确定 kube-dns 中 DNS 问题的来源
dial tcp: i/o timeout
、no such
host
或 Could not resolve host
等错误通常表示 kube-dns 无法解析查询。
如果您看到了其中某个错误,但不知道原因,请参阅以下部分,帮助您找出原因。以下各部分的排列顺序是从最有可能帮助到您的步骤开始,因此请按顺序尝试各部分。
检查 kube-dns Pod 是否正在运行
Kube-dns Pod 对集群内的名称解析至关重要。如果这些服务未运行,您可能会遇到 DNS 解析问题。
如需验证 kube-dns Pod 是否正在运行且最近未重启,请查看这些 Pod 的状态:
kubectl get pods -l k8s-app=kube-dns -n kube-system
输出类似于以下内容:
NAME READY STATUS RESTARTS AGE
kube-dns-POD_ID_1 5/5 Running 0 16d
kube-dns-POD_ID_2 0/5 Terminating 0 16d
在此输出中,POD_ID_1
和 POD_ID_2
代表自动附加到 kube-dns Pod 的唯一标识符。
如果输出显示您的任何 kube-dns Pod 的状态不是 Running
,请按以下步骤操作:
使用管理员活动审核日志调查最近是否发生了任何更改,例如集群或节点池版本升级,或 kube-dns ConfigMap 的更改。如需详细了解审核日志,请参阅 GKE 审核日志记录信息。如果您发现了更改,请还原更改,然后再次查看 Pod 的状态。
如果您没有发现任何相关的近期更改,请调查 kube-dns Pod 运行的节点上是否出现了 OOM 错误。如果您在 Cloud Logging 日志消息中看到类似于以下内容的错误,则表示这些 Pod 遇到了 OOM 错误:
Warning: OOMKilling Memory cgroup out of memory
如需解决此错误,请参阅错误消息:“Warning: OOMKilling Memory cgroup out of memory”。
如果您没有找到任何 OOM 错误消息,请重启 kube-dns 部署:
kubectl rollout restart deployment/kube-dns --namespace=kube-system
重启部署后,检查您的 kube-dns Pod 是否正在运行。
如果这些步骤不起作用,或者您的所有 kube-dns Pod 的状态均为 Running
,但您仍然遇到 DNS 问题,请检查 /etc/resolv.conf
文件是否配置正确。
检查 /etc/resolv.conf
是否已正确配置
查看遇到 DNS 问题的 Pod 的 /etc/resolv.conf
文件,并确保其中包含的条目正确无误:
查看 pod 的
/etc/resolv.conf
文件:kubectl exec -it POD_NAME -- cat /etc/resolv.conf
将 POD_NAME 替换为遇到 DNS 问题的 Pod 的名称。如果有多个 Pod 存在问题,请针对每个 Pod 重复执行本部分中的步骤。
如果 Pod 二进制文件不支持
kubectl exec
命令,此命令可能会失败。如果出现这种情况,请创建一个简单的 Pod 用作测试环境。通过此过程,您可以在存在问题的 Pod 所在的命名空间中运行测试 Pod。验证
/etc/resolv.conf
文件中的域名服务器 IP 地址是否正确:- 使用主机网络的 Pod 应使用节点的
/etc/resolv.conf
文件中的值。域名服务器 IP 地址应为169.254.169.254
。 对于不使用主机网络的 Pod,kube-dns 服务 IP 地址应与域名服务器 IP 地址相同。如需比较 IP 地址,请完成以下步骤:
获取 kube-dns 服务的 IP 地址:
kubectl get svc kube-dns -n kube-system
输出类似于以下内容:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 192.0.2.10 <none> 53/UDP,53/TCP 64d
记下“集群 IP”列中的值。在此示例中,该网址为
192.0.2.10
。将 kube-dns 服务 IP 地址与
/etc/resolv.conf
文件中的 IP 地址进行比较:# cat /etc/resolv.conf search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_NAME google.internal nameserver 192.0.2.10 options ndots:5
在此示例中,这两个值匹配,因此问题不是由错误的域名服务器 IP 地址导致的。
但是,如果 IP 地址不匹配,则表示在应用 Pod 的清单中配置了
dnsConfig
字段。如果
dnsConfig.nameservers
字段中的值正确无误,请检查您的 DNS 服务器,确保其正常运行。如果您不想使用自定义域名服务器,请移除该字段并滚动重启 pod:
kubectl rollout restart deployment POD_NAME
将
POD_NAME
替换为您的 Pod 名称。
- 使用主机网络的 Pod 应使用节点的
验证
/etc/resolv.conf
中的search
和ndots
条目。确保没有拼写错误、过时配置,并且失败的请求指向正确命名空间中的现有服务。
执行 DNS 查找
确认 /etc/resolv.conf
配置正确且 DNS 记录正确后,请使用 dig 命令行工具从报告 DNS 错误的 Pod 执行 DNS 查找:
通过在 Pod 中打开 shell 直接查询 Pod:
kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
替换以下内容:
POD_NAME
:报告 DNS 错误的 Pod 的名称。NAMESPACE_NAME
:Pod 所属的命名空间。SHELL_NAME
:您要打开的 shell 的名称。例如sh
或/bin/bash
。
如果您的 Pod 不允许使用
kubectl exec
命令,或者 Pod 没有 dig 二进制文件,此命令可能会失败。如果发生这种情况,请使用已安装 dig 的映像创建一个测试 Pod:kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
检查 Pod 是否可以正确解析集群的内部 DNS 服务:
dig kubernetes
由于
/etc/resolv.conf
文件指向 kube-dns 服务 IP 地址,因此当您运行此命令时,DNS 服务器就是 kube-dns 服务。您应该会看到包含 Kubernetes API 服务 IP 地址(通常类似于
10.96.0.1
)的成功 DNS 响应。如果您看到SERVFAIL
或没有响应,这通常表示 kube-dns Pod 无法解析内部服务名称。检查 kube-dns 服务是否可以解析外部域名:
dig example.com
如果特定 kube-dns Pod 在响应 DNS 查询时遇到问题,请检查该 Pod 是否可以解析外部域名:
dig example.com @KUBE_DNS_POD_IP
将
KUBE_DNS_POD_IP
替换为 kube-dns Pod 的 IP 地址。如果您不知道此 IP 地址的值,请运行以下命令:kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
IP 地址位于
IP
列中。如果命令的解析成功,您会看到
status: NOERROR
和 A 记录的详细信息,如下例所示:; <<>> DiG 9.16.27 <<>> example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31256 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;example.com. IN A ;; ANSWER SECTION: example.com. 30 IN A 93.184.215.14 ;; Query time: 6 msec ;; SERVER: 10.76.0.10#53(10.76.0.10) ;; WHEN: Tue Oct 15 16:45:26 UTC 2024 ;; MSG SIZE rcvd: 56
退出 shell:
exit
如果上述任一命令失败,请对 kube-dns 部署进行滚动重启:
kubectl rollout restart deployment/kube-dns --namespace=kube-system
重启完成后,请重新尝试 dig 命令,看看它们现在能否成功执行。如果仍然失败,请继续进行数据包捕获。
捕获数据包
进行数据包捕获,以验证 kube-dns Pod 是否正在正确接收和回答 DNS 查询:
使用 SSH 连接到运行 kube-dns Pod 的节点。例如:
在 Google Cloud 控制台中,前往虚拟机实例页面。
找到要连接到的节点。如果您不知道 kube-dns Pod 上节点的名称,请运行以下命令:
kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
节点的名称列在 Node 列中。
在连接列中,点击 SSH。
在终端中,启动预安装的调试工具 toolbox:
toolbox
在根提示符下,安装
tcpdump
软件包:apt update -y && apt install -y tcpdump
使用
tcpdump
对 DNS 流量进行数据包捕获:tcpdump -i eth0 port 53" -w FILE_LOCATION
将
FILE_LOCATION
替换为您要保存屏幕截图的位置的路径。查看数据包捕获内容。检查是否存在目标 IP 地址与 kube-dns 服务 IP 地址匹配的数据包。这可确保 DNS 请求到达正确的目标以进行解析。如果未看到 DNS 流量到达正确的 Pod,则可能表示存在阻止请求的网络政策。
检查网络政策
限制性网络政策有时可能会干扰 DNS 流量。如需验证 kube-system 命名空间中是否存在网络政策,请运行以下命令:
kubectl get networkpolicy -n kube-system
如果您找到网络政策,请对其进行审核,确保该政策允许进行必要的 DNS 通信。例如,如果您有一项网络政策会阻止所有出站流量,该政策也会阻止 DNS 请求。
如果输出为 No resources found in kube-system namespace
,则表示您没有任何网络政策,因此可以排除此原因。调查日志有助于您发现更多失败点。
启用临时 DNS 查询日志记录
为了帮助您找出 DNS 响应不正确等问题,请暂时启用 DNS 查询的调试日志记录。
此过程会消耗大量资源,因此我们建议您在收集合适的日志示例后停用此日志记录。
调查 kube-dns Pod
使用 Cloud Logging 查看 kube-dns Pod 如何接收和解析 DNS 查询。
如需查看与 kube-dns Pod 相关的日志条目,请完成以下步骤:
在 Google Cloud 控制台中,前往 Logs Explorer 页面。
在查询窗格中,输入以下过滤条件以查看与 kube-dns 容器相关的事件:
resource.type="k8s_container" resource.labels.namespace_name="kube-system" resource.labels.Pod_name:"kube-dns" resource.labels.cluster_name="CLUSTER_NAME" resource.labels.location="CLUSTER_LOCATION"
替换以下内容:
CLUSTER_NAME
:kube-dns Pod 所属集群的名称。CLUSTER_LOCATION
:您的集群的位置。
点击运行查询。
查看输出。以下示例输出显示了您可能会看到的一种可能错误:
{ "timestamp": "2024-10-10T15:32:16.789Z", "severity": "ERROR", "resource": { "type": "k8s_container", "labels": { "namespace_name": "kube-system", "Pod_name": "kube-dns", "cluster_name": "CLUSTER_NAME", "location": "CLUSTER_LOCATION" } }, "message": "Failed to resolve 'example.com': Timeout." },
在此示例中,kube-dns 无法在合理的时间内解析
example.com
。此类错误可能由多种问题导致。例如,上游服务器在 kube-dns ConfigMap 中可能配置有误,或者网络流量可能较高。
如果您未启用 Cloud Logging,请改为查看 Kubernetes 日志:
Pod=$(kubectl get Pods -n kube-system -l k8s-app=kube-dns -o name | head -n1)
kubectl logs -n kube-system $Pod -c dnsmasq
kubectl logs -n kube-system $Pod -c kubedns
kubectl logs -n kube-system $Pod -c sidecar
调查 kube-dns ConfigMap 中的近期更改
如果您在集群中突然遇到 DNS 解析失败问题,其中一个原因可能是对 kube-dns ConfigMap 所做的配置更改不正确。特别是,对存根网域和上游服务器定义的配置更改可能会导致问题。
如需检查桩网域设置的更新,请完成以下步骤:
在 Google Cloud 控制台中,前往 Logs Explorer 页面。
在查询窗格中,输入以下查询:
resource.labels.cluster_name="clouddns" resource.type="k8s_container" resource.labels.namespace_name="kube-system" labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated stubDomains to"
点击运行查询。
查看输出。如果有任何更新,输出类似于以下内容:
Updated stubDomains to map[example.com: [8.8.8.8 8.8.4.4 1.1.3.3 1.0.8.111]]
如果您看到更新,请展开相应结果,详细了解相关更改。 验证所有存根网域及其相应的上游 DNS 服务器是否已正确定义。如果此处的条目不正确,可能会导致这些网域无法解析。
如需检查上游服务器是否发生了更改,请完成以下步骤:
在 Google Cloud 控制台中,前往 Logs Explorer 页面。
在查询窗格中,输入以下查询:
resource.labels.cluster_name="clouddns" resource.type="k8s_container" resource.labels.namespace_name="kube-system" labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated upstreamNameservers to"
点击运行查询。
查看输出。如果发生了任何更改,输出将类似于以下内容:
Updated upstreamNameservers to [8.8.8.8]
展开相应结果,详细了解相关变更。验证上游 DNS 服务器列表是否准确,以及这些服务器是否可从集群访问。如果这些服务器不可用或配置错误,常规 DNS 解析可能会失败。
如果您检查了桩网域和上游服务器的更改,但没有找到任何结果,请使用以下过滤条件检查所有更改:
resource.type="k8s_cluster"
protoPayload.resourceName:"namespaces/kube-system/configmaps/kube-dns"
protoPayload.methodName=~"io.k8s.core.v1.configmaps."
查看列出的所有更改,看看它们是否导致了错误。
与 Cloud Customer Care 团队联系
如果您已完成上述部分,但仍无法诊断问题原因,请与 Cloud Customer Care 团队联系。
解决常见问题
如果您遇到了特定错误或问题,请参考以下部分中的建议。
问题:DNS 间歇性超时
如果您发现在 DNS 流量增加或开始营业时出现间歇性 DNS 解析超时,请尝试以下解决方案来优化 DNS 性能:
检查集群上运行的 kube-dns Pod 的数量,并将其与 GKE 节点的总数进行比较。如果资源不足,请考虑扩容 kube-dns Pod。
如需缩短平均 DNS 查找时间,请启用 NodeLocal DNS Cache。
对外部名称进行 DNS 解析可能会导致 kube-dns Pod 过载。如需减少查询数量,请调整
/etc/resolv.conf
文件中的ndots
设置。ndots
表示域名中必须显示的点数,以便在初始绝对查询之前解析查询。以下示例是应用 Pod 的
/etc/resolv.conf
文件:search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_ID.internal google.internal nameserver 10.52.16.10 options ndots:5
在此示例中,kube-dns 会在查询的网域中查找五个圆点。如果 Pod 针对
example.com
发出 DNS 解析调用,则日志类似于以下示例:"A IN example.com.default.svc.cluster.local." NXDOMAIN "A IN example.com.svc.cluster.local." NXDOMAIN "A IN example.com.cluster.local." NXDOMAIN "A IN example.com.google.internal." NXDOMAIN "A IN example.com.c.PROJECT_ID.internal." NXDOMAIN "A IN example.com." NOERROR
如需解决此问题,请将 ndots 的值更改为
1
,以便仅查找单个点,或者在您查询或使用的网域末尾附加一个点 (.
)。例如:dig example.com.
问题:某些节点的 DNS 查询会间歇性失败
如果您发现某些节点的 DNS 查询会间歇性失败,则可能会看到以下症状:
- 当您对 kube-dns 服务 IP 地址或 Pod IP 地址运行 dig 命令时,DNS 查询会间歇性失败并超时。
- 在与 kube-dns Pod 位于同一节点上的 Pod 中运行 dig 命令会失败。
如需解决此问题,请完成以下步骤:
- 执行连接性测试。将有问题的 Pod 或节点设置为来源,将目标设置为 kube-dns Pod 的 IP 地址。这样,您就可以检查自己是否已设置了允许此类流量的必要防火墙规则。
如果测试未成功,并且流量被防火墙规则阻止,请使用 Cloud Logging 列出对防火墙规则所做的任何手动更改。查找导致屏蔽特定类型流量的更改:
如果防火墙规则没有任何更改,请检查节点池版本,确保其与控制平面和其他正常运行的节点池兼容。如果集群的任一节点池比控制平面高两个次要版本,则可能会导致问题。如需详细了解此不兼容性,请参阅节点版本与控制平面版本不兼容。
如需确定请求是否发送到正确的 kube-dns 服务 IP,请捕获有问题节点上的网络流量,并过滤出端口 53(DNS 流量)。捕获 kube-dns Pod 本身上的流量,以了解请求是否到达预期的 Pod 以及是否成功解析。
后续步骤
- 如需了解诊断 Kubernetes DNS 问题的一般信息,请参阅调试 DNS 解析。
- 如果您需要其他帮助,请与 Cloud Customer Care 联系。