本页面介绍如何解决 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
此消息表明 Kubernetes 因资源消耗过多而终止了某个进程。Kubernetes 会根据资源请求调度 Pod,但允许 Pod 消耗不超过其资源限制的资源。如果限制高于请求或没有限制,Pod 的资源使用量可能会超过系统的资源。
如需解决此错误,您可以删除有问题的工作负载,也可以设置内存或 CPU 限制。如需详细了解如何设置限制,请参阅 Kubernetes 文档中的为 Pod 和容器管理资源。
如果您没有发现任何 OOM 错误消息,请重启 kube-dns Deployment:
kubectl rollout restart deployment/kube-dns --namespace=kube-system
重启 Deployment 后,检查 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 Service IP 地址应与域名服务器 IP 地址相同。如需比较 IP 地址,请完成以下步骤:
获取 kube-dns Service 的 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
记下“Cluster IP”列中的值。在此示例中为
192.0.2.10
。将 kube-dns Service 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 Service:
dig kubernetes
由于
/etc/resolv.conf
文件指向 kube-dns Service IP 地址,因此当您运行此命令时,DNS 服务器就是 kube-dns Service。您应该会看到成功的 DNS 响应,其中包含 Kubernetes API Service 的 IP 地址(通常类似于
10.96.0.1
)。如果您看到SERVFAIL
或没有响应,这通常表示 kube-dns Pod 无法解析内部服务名称。检查 kube-dns Service 是否可以解析外部域名:
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 Deployment 执行滚动重启:
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
节点的名称会列在节点列中。
在连接列中,点击 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 Service 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 创建一个 Pod。对 kube-dns Deployment 所做的任何更改都会自动还原。
启用临时 DNS 查询日志记录是一个需要耗费大量资源的过程,因此我们建议您在收集到合适的日志样本后立即删除您创建的 Pod。
如需启用临时 DNS 查询日志记录,请完成以下步骤:
检索 kube-dns Pod,并将其存储在名为
POD
的变量中:POD=$(kubectl -n kube-system get pods --selector=k8s-app=kube-dns -o jsonpath="{.items[0].metadata.name}")
创建一个名为
kube-dns-debug
的 Pod。此 Pod 是存储在POD
变量中的 Pod 的副本,但启用了 dnsmasq 日志记录。此命令不会修改原始的 kube-dns Pod:kubectl apply -f <(kubectl get pod -n kube-system ${POD} -o json | jq -e ' ( (.spec.containers[] | select(.name == "dnsmasq") | .args) += ["--log-queries"] ) | (.metadata.name = "kube-dns-debug") | (del(.metadata.labels."pod-template-hash")) ')
检查日志:
kubectl logs -f --tail 100 -c dnsmasq -n kube-system kube-dns-debug
您也可以在 Cloud Logging 中看到查询。
查看 DNS 查询日志后,删除
kube-dns-debug
Pod:kubectl -n kube-system delete pod kube-dns-debug
调查 kube-dns Pod
使用 Cloud Logging 查看 kube-dns Pod 如何接收和解析 DNS 查询。
如需查看与 kube-dns Pod 相关的日志条目,请完成以下步骤:
在 Google Cloud 控制台中,转到日志浏览器页面。
在查询窗格中,输入以下过滤条件以查看与 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 控制台中,转到日志浏览器页面。
在查询窗格中,输入以下查询:
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 控制台中,转到日志浏览器页面。
在查询窗格中,输入以下查询:
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 缓存。
外部域名的 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 Service 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 联系。