本页面介绍如何使用 NodeLocal DNSCache 缩短在 Google Kubernetes Engine (GKE) 集群中执行 DNS 查找的延迟时间。
对于 GKE Autopilot 集群,NodeLocal DNSCache 默认启用且不能覆盖。
架构
NodeLocal DNSCache 是一个 GKE 插件,除了 kube-dns 之外,您还可以运行该插件。
GKE 将 NodeLocal DNSCache 作为 DaemonSet 实现,DaemonSet 会在集群中的每个节点上运行 DNS 缓存。
当 Pod 发出 DNS 请求时,该请求会转到与 Pod 相同的节点上运行的 DNS 缓存。如果该缓存无法解析该 DNS 请求,则会根据查询目标将该请求转发到以下位置之一:
- kube-dns:集群 DNS 网域 (
cluster.local
) 的所有查询都将转发到 kube-dns。node-local-dns Pod 使用 kube-dns-upstream 服务访问 kube-dns Pod。在下图中,kube-dns 服务的 IP 地址为10.0.0.10:53
。 - 自定义存根网域或上行域名服务器:查询直接从 NodeLocal DNSCache Pod 转发。
- Cloud DNS:所有其他查询均会转发到与发起查询的 Pod 所在节点上运行的本地元数据服务器。本地元数据服务器会访问 Cloud DNS。
在现有集群上启用 NodeLocal DNSCache 时,GKE 会按照节点升级过程重新创建所有运行 GKE 1.15 及更高版本的集群节点。
重新创建节点后,GKE 会自动向节点添加 addon.gke.io/node-local-dns-ds-ready=true
标签。您不得手动将此标签添加到集群节点。
NodeLocal DNSCache 的优点
NodeLocal DNSCache 具有以下优势:
- 减少了平均 DNS 查找时间
- 从 Pod 到其本地缓存的连接不会创建 conntrack 表条目。这样可以防止由于 conntrack 表耗尽和竞态条件而导致连接中断和连接被拒绝。
- 您可以将 NodeLocal DNSCache 与 Cloud DNS for GKE 搭配使用。
- 外部网址(不引用集群资源的网址)的 DNS 查询会绕过 kube-dns 而直接转发到本地 Cloud DNS 元数据服务器。
- 本地 DNS 缓存会自动选取 kube-dns ConfigMap 中指定的存根网域和上行域名服务器。
要求和限制
- NodeLocal DNSCache 会消耗集群的每个节点上的计算资源。
- Windows Server 节点池不支持 NodeLocal DNSCache。
- NodeLocal DNSCache 需要 GKE 1.15 或更高版本。
- NodeLocal DNSCache 使用 TCP 访问 kube-dns Pod。
- NodeLocal DNSCache 在 GKE 1.18 版或更高版本上使用 TCP 和 UDP 访问
upstreamServers
和stubDomains
。DNS 服务器必须可通过 TCP 和 UDP 访问。 - 系统会在以下时间段缓存 DNS 记录:
- 记录的存留时间 (TTL) 或 30 秒(后者适用于 TTL 超过 30 秒的情况)。
- 5 秒(如果 DNS 响应为
NXDOMAIN
)。
- NodeLocal DNSCache Pod 会侦听节点上的端口 53、9253、9353 和 8080。如果您运行任何其他
hostNetwork
Pod 或使用这些端口配置hostPorts
,则 NodeLocal DNSCache 会失败并发生 DNS 错误。使用 GKE Dataplane V2 和 Cloud DNS for GKE 时,NodeLocal DNSCache Pod 不会使用hostNetwork
模式。 - 本地 DNS 缓存仅在运行 GKE 1.15 及更高版本的节点池上运行。如果您在具有运行早期版本的节点的集群中启用 NodeLocal DNSCache,则这些节点上的 Pod 会使用 kube-dns。
启用 NodeLocal DNSCache
对于 Autopilot 集群,NodeLocal DNSCache 默认处于启用状态且不能覆盖。
对于 Standard 集群,您可以使用 Google Cloud CLI 在新集群或现有集群上启用 NodeLocal DNSCache。您可以使用 Google Cloud 控制台在新集群中启用 NodeLocal DNSCache。
gcloud
在新集群中启用 NodeLocal DNSCache
如需在新集群中启用 NodeLocal DNSCache,请使用带有参数 NodeLocalDNS
的 --addons
标志:
gcloud container clusters create CLUSTER_NAME \
--location=COMPUTE_LOCATION \
--addons=NodeLocalDNS
替换以下内容:
CLUSTER_NAME
:新集群的名称。COMPUTE_LOCATION
:集群的 Compute Engine 位置。
在现有集群中启用 NodeLocal DNSCache
如需在现有集群中启用 NodeLocal DNSCache,请使用带有参数 NodeLocalDNS=ENABLED
的 --update-addons
标志:
gcloud container clusters update CLUSTER_NAME \
--update-addons=NodeLocalDNS=ENABLED
替换以下内容:
CLUSTER_NAME
:您的集群的名称。
控制台
如需在新集群上启用 NodeLocal DNSCache,请按以下步骤操作:
转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。
点击“标准”旁边的配置。
根据需要配置集群。
在导航窗格中,点击网络。
在高级网络选项部分中,选中启用 NodeLocal DNSCache 复选框。
点击创建。
验证 NodeLocal DNSCache 是否已启用
您可以通过列出 node-local-dns
Pod 来验证 NodeLocal DNSCache 是否正在运行:
kubectl get pods -n kube-system -o wide | grep node-local-dns
输出内容类似如下:
node-local-dns-869mt 1/1 Running 0 6m24s 10.128.0.35 gke-test-pool-69efb6b8-5d7m <none> <none>
node-local-dns-htx4w 1/1 Running 0 6m24s 10.128.0.36 gke-test-pool-69efb6b8-wssk <none> <none>
node-local-dns-v5njk 1/1 Running 0 6m24s 10.128.0.33 gke-test-pool-69efb6b8-bhz3 <none> <none>
输出会为运行 GKE 1.15 或更高版本的每个节点显示一个 node-local-dns
Pod。
停用 NodeLocal DNSCache
您可以使用以下命令停用 NodeLocal DNSCache:
gcloud container clusters update CLUSTER_NAME \
--update-addons=NodeLocalDNS=DISABLED
替换以下内容:
CLUSTER_NAME
:要停用的集群的名称。
排查 NodeLocal DNSCache 问题
如需了解诊断 Kubernetes DNS 问题的一般信息,请参阅调试 DNS 解析。
NodeLocal DNSCache 未立即启用
在现有集群上启用 NodeLocal DNSCache 时,如果集群配置了维护期或排除选项,则 GKE 可能不会立即更新节点。 如需了解详情,请参阅节点重新创建和维护窗口的注意事项。
如果您不想等待,可通过调用 gcloud container clusters upgrade
命令并使用节点池已经运行的 GKE 版本传递 --cluster-version
标志,将更改手动应用到节点。您必须将 Google Cloud CLI 用于此临时解决方法。
将 NodeLocal DNSCache 与 Cloud DNS 搭配使用
如果您将 NodeLocal DNSCache 与 Cloud DNS 搭配使用,则集群会使用域名服务器 IP 地址 169.254.20.10
,如下图所示:
因此,kube-dns
Service 的 IP 地址可能与您的 Pod 使用的域名服务器 IP 地址不同。这种 IP 地址差异是正常的,因为 Cloud DNS 需要 169.254.20.10
域名服务器 IP 地址才能正常运行。
如需检查 IP 地址,请运行以下命令:
查看
kube-dns
Service 的 IP 地址:kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
输出为
kube-dns
的 IP 地址,例如10.0.0.10:53
在 Pod 中打开 shell 会话:
kubectl exec -it POD_NAME -- /bin/bash
在 Pod shell 会话中,读取
/etc/resolv.conf
文件的内容:cat /etc/resolv.conf
输出为
169.254.20.10
使用 NodeLocal DNSCache 的网络政策
如果您将网络政策与 NodeLocal DNSCache 搭配使用,并且您没有使用 Cloud DNS 或 GKE Dataplane V2,则您必须配置规则来允许工作负载和 node-local-dns
Pod 发送 DNS 查询。
在您的清单中使用 ipBlock
规则来允许在您的 Pod 和 kube-dns 之间进行通信。
以下清单说明了一项使用 ipBlock
规则的网络政策:
spec:
egress:
- ports:
- port: 53
protocol: TCP
- port: 53
protocol: UDP
to:
- ipBlock:
cidr: KUBE_DNS_SVC_CLUSTER_IP/32
podSelector: {}
policyTypes:
- Egress
将 KUBE_DNS_SVC_CLUSTER_IP
替换为 kube-dns 服务的 IP 地址。您可以使用以下命令获取 kube-dns 服务的 IP 地址:
kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
已知问题
使用 NodeLocal DNSCache 和 GKE Dataplane V2 时,ClusterFirstWithHostNet dnsPolicy 中的 DNS 超时
在使用 GKE Dataplane V2 和 NodeLocal DNSCache 的集群上,hostNetwork
设置为 true
且 dnsPolicy
设置为 ClusterFirstWithHostNet
的 Pod 无法访问集群 DNS 后端。DNS 日志可能包含类似如下内容的条目:
nslookup: write to 'a.b.c.d': Operation not permitted
;; connection timed out; no servers could be reached
输出表明 DNS 请求无法连接到后端服务器。
解决方法是为 hostNetwork
Pod 设置 dnsPolicy
和 dnsConfig
:
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- KUBE_DNS_UPSTREAM
searches:
- cluster.local
- svc.cluster.local
- NAMESPACE.svc.cluster.local
- c.PROJECT_ID.internal
- google.internal
options:
- name: ndots
value: "5"
替换以下内容:
NAMESPACE
:hostNetwork
pod 的命名空间。PROJECT_ID
:您的 Google Cloud 项目的 ID。KUBE_DNS_UPSTREAM
:上游 kube-dns 服务的 ClusterIP 地址。您可以使用以下命令获取此值:kubectl get svc -n kube-system kube-dns-upstream -o jsonpath="{.spec.clusterIP}"
Pod 的 DNS 请求现在可以访问 kube-dns 并绕过 NodeLocal DNSCache。
NodeLocal DNSCache 超时错误
在启用了 NodeLocal DNSCache 的集群上,日志可能包含类似于以下内容的条目:
[ERROR] plugin/errors: 2 <hostname> A: read tcp <node IP: port>-><kubedns IP>:53: i/o timeout
输出中包含 kube-dns-upstream
集群 IP 服务的 IP 地址。在此示例中,未在 2 秒钟内从 kube-dns 收到对 DNS 请求的响应。这可能是由下列某种原因造成的:
- 底层网络连接问题。
- 来自工作负载的 DNS 查询显著增加或由于节点池扩容。
因此,现有的 kube-dns
Pod 无法及时处理所有请求。解决方法是通过调整自动扩缩参数来增加 kube-dns 副本的数量。
纵向扩容 kube-dns
您可以针对 nodesPerReplica
使用较低的值,以确保在集群节点纵向扩容时创建更多的 kube-dns Pod。我们强烈建议设置明确的 max
值,以确保 GKE 控制平面虚拟机 (VM) 不会因监控 Kubernetes API 的 kube-dns Pod 数量太多而不堪重负。
您可以将 max
设置为集群中的节点数。如果集群的节点数量超过 500 个,请将 max
设置为 500。
对于 Standard 集群,您可以通过修改 kube-dns-autoscaler
ConfigMap 来修改 kube-dns 副本的数量。Autopilot 集群中不支持此配置。
kubectl edit configmap kube-dns-autoscaler --namespace=kube-system
输出类似于以下内容:
linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'
kube-dns 副本数的计算公式如下:
副本 = max( ceil( cores × 1/coresPerReplica ) , ceil( nodes × 1/nodesPerReplica ), maxValue )
如需纵向扩容,请将 nodesPerReplica
更改为较小的值,并添加 max
值。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'
此配置会为集群中的每 8 个节点创建 1 个 kube-dns pod。24 个节点的集群会有 3 个副本,40 个节点集群会有 5 个副本。集群增加超过 120 个节点,kube-dns 副本数不会增加到超过 15(即 max
值)。
如需确保集群中 DNS 可用性的基准级别,请为 kube-dns 设置最小副本数。
具有 min
字段的 kube-dns-autoscaler
ConfigMap 输出类似于以下内容:
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'
后续步骤
- 简要了解 GKE 如何提供托管式 DNS。
- 阅读服务和 Pod 的 DNS,大致了解如何在 Kubernetes 集群中使用 DNS。
- 了解如何使用 Cloud DNS for GKE。