如果您在標準叢集中執行應用程式,kube-dns 是預設的 DNS 供應商,可協助您啟用服務探索和通訊功能。本文說明如何使用 kube-dns 管理 DNS,包括架構、設定,以及在 GKE 環境中最佳化 DNS 解析的最佳做法。
本文適用於負責管理 GKE 中 DNS 的開發人員、管理員和架構師。如要瞭解 Google Cloud的常見角色和工作,請參閱「常見的 GKE Enterprise 使用者角色和工作」。
開始之前,請務必先熟悉 Kubernetes 服務和一般 DNS 概念。
瞭解 kube-dns 架構
kube-dns 會在 GKE 叢集內運作,以便在 Pod 和服務之間解析 DNS。
下圖顯示 Pod 如何與 kube-dns Service 互動:
重要元件
kube-dns 包含下列重要元件:
kube-dnsPod:這些 Pod 會執行kube-dns伺服器軟體。這些 Pod 的多個副本會在kube-system命名空間中執行,提供高可用性和備援功能。kube-dns服務:這個 Kubernetes 服務 (類型為ClusterIP) 會將kube-dnsPod 分組,並將這些 Pod 公開為單一穩定的端點。ClusterIP會做為叢集的 DNS 伺服器,Pod 會使用這個伺服器傳送 DNS 查詢。kube-dns每個無標題服務最多支援 1,000 個端點。kube-dns-autoscaler:這個 Pod 會根據叢集大小 (包括節點和 CPU 核心數量),調整副本數量。kube-dns這種做法可確保kube-dns能處理不同的 DNS 查詢負載。
內部 DNS 解析
當 Pod 需要解析叢集網域內的 DNS 名稱 (例如 myservice.my-namespace.svc.cluster.local) 時,會發生下列程序:
- Pod DNS 設定:每個節點上的
kubelet會設定 Pod 的/etc/resolv.conf檔案。這個檔案會使用kube-dns服務的ClusterIP做為名稱伺服器。 - DNS 查詢:Pod 會將 DNS 查詢傳送至
kube-dnsService。 - 名稱解析:
kube-dns接收查詢。並在內部 DNS 記錄中查詢對應的 IP 位址,然後回應 Pod。 - 通訊:Pod 接著會使用已解析的 IP 位址,與目標 Service 通訊。
外部 DNS 解析
當 Pod 需要解析外部 DNS 名稱或叢集網域外的名稱時,kube-dns 會做為遞迴解析器。並將查詢轉送至 ConfigMap 檔案中設定的上游 DNS 伺服器。您也可以為特定網域設定自訂解析程式,也就是所謂的存根網域。這項設定會指示 kube-dns 將這些網域的要求轉送至特定上游 DNS 伺服器。
設定 Pod DNS
在 GKE 中,每個節點上的 kubelet 代理程式會為該節點上執行的 Pod 設定 DNS 設定。
設定 /etc/resolv.conf 檔案
GKE 建立 Pod 時,kubelet 代理程式會修改 Pod 的 /etc/resolv.conf 檔案。這個檔案會設定 DNS 伺服器以解析名稱,並指定搜尋網域。根據預設,kubelet 會將叢集的內部 DNS 服務 kube-dns 設定為 Pod 的名稱伺服器。並在檔案中填入搜尋網域。您可以在 DNS 查詢中使用不合格的名稱,舉例來說,如果 Pod 查詢 myservice,Kubernetes 會先嘗試解析 myservice.default.svc.cluster.local,然後解析 myservice.svc.cluster.local,接著解析 search 清單中的其他網域。
以下範例顯示預設的 /etc/resolv.conf 設定:
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local c.my-project-id.internal google.internal
options ndots:5
這個檔案包含下列項目:
nameserver:定義kube-dns服務的ClusterIP。search:定義在 DNS 查詢期間附加至不合格名稱的搜尋網域。options ndots:5:設定 GKE 判斷名稱是否完全合格的門檻。如果名稱包含五個以上的點,即視為完整名稱。
設定為 hostNetwork: true 的 Pod 會從主機繼承 DNS 設定,不會直接查詢 kube-dns。
自訂kube-dns
kube-dns 提供強大的預設 DNS 解析功能。您可以根據特定需求調整其行為,例如提高解析效率或使用偏好的 DNS 解析器。如要設定存根網域和上游名稱伺服器,請修改 kube-system 命名空間中的 kube-dns ConfigMap。
修改 kube-dns ConfigMap
如要修改 kube-dns ConfigMap,請執行下列操作:
開啟 ConfigMap 進行編輯:
kubectl edit configmap kube-dns -n kube-system在
data區段中,將stubDomains和upstreamNameservers欄位新增至:apiVersion: v1 kind: ConfigMap metadata: labels: addonmanager.kubernetes.io/mode: EnsureExists name: kube-dns namespace: kube-system data: stubDomains: | { "example.com": [ "8.8.8.8", "8.8.4.4" ], "internal": [ # Required if your upstream nameservers can't resolve GKE internal domains "169.254.169.254" # IP of the metadata server ] } upstreamNameservers: | [ "8.8.8.8", # Google Public DNS "1.1.1.1" # Cloudflare DNS ]儲存 ConfigMap。
kube-dns會自動重新載入設定。
Stub 網域
存根網域可讓您為特定網域定義自訂 DNS 解析器。當 Pod 查詢該存根網域中的名稱時,kube-dns 會將查詢轉送至指定的解析器,而不是使用預設的解析機制。
在 kube-dns ConfigMap 中加入 stubDomains 區段。
本節會指定網域和對應的上游名稱伺服器。
kube-dns 接著會將該網域內名稱的查詢轉送至指定伺服器。舉例來說,您可以將 internal.mycompany.com 的所有 DNS 查詢轉送至 192.168.0.10,並將 "internal.mycompany.com": ["192.168.0.10"] 新增至 stubDomains。
為 Stub 網域 (例如 example.com) 設定自訂解析器時,kube-dns 會將該網域的所有名稱解析要求 (包括 *.example.com 等子網域) 轉送至指定伺服器。
上游名稱伺服器
您可以設定 kube-dns 使用自訂上游名稱伺服器,解析外部網域名稱。這項設定會指示 kube-dns 將所有 DNS 要求 (叢集內部網域 (*.cluster.local) 的要求除外) 轉送至指定的上游伺服器。自訂上游伺服器可能無法解析 metadata.internal 和 *.google.internal 等內部網域。如果您啟用 Workload Identity Federation for GKE,或有工作負載依附於這些網域,請在 ConfigMap 中為 internal 新增虛設常式網域。使用中繼資料伺服器的 IP 位址 169.254.169.254,做為這個存根網域的解析程式。
管理自訂 kube-dns 部署作業
在標準 GKE 中,kube-dns 會以 Deployment 形式執行。自訂部署作業是指叢集管理員可以控管部署作業,並根據需求自訂部署作業,而不是使用 GKE 提供的預設部署作業。kube-dns
自訂部署作業的原因
請考慮自訂 kube-dns 部署作業,原因如下:
- 資源分配:微調 Pod 的 CPU 和記憶體資源,在 DNS 流量高的叢集中最佳化效能。
kube-dns - 映像檔版本:使用特定版本的
kube-dns映像檔,或改用 CoreDNS 等替代 DNS 供應商。 - 進階設定:自訂記錄層級、安全性政策和 DNS 快取行為。
自訂部署項目的自動調度資源
內建 kube-dns-autoscaler 適用於預設的 kube-dns 部署作業。如果您建立自訂 kube-dns Deployment,內建的自動配置器不會管理該 Deployment。因此,您必須設定專門用於監控及調整自訂 Deployment 副本數量的獨立自動調整器。這個方法是在叢集中建立及部署自己的自動調度資源設定。
管理自訂 Deployment 時,您必須負責所有元件,例如確保自動調整比例的映像檔為最新版本。使用過時的元件可能會導致效能降低或 DNS 失敗。
如需如何設定及管理自有部署作業的詳細操作說明,請參閱「設定自訂 kube-dns 部署作業」。kube-dns
疑難排解
如要瞭解如何排解 kube-dns 問題,請參閱下列頁面:
- 如需 GKE 中
kube-dns的相關建議,請參閱「排解 GKE 中的kube-dns問題」。 - 如需診斷 Kubernetes DNS 問題的一般建議,請參閱「偵錯 DNS 解析」。
最佳化 DNS 解析
本節說明在 GKE 中管理 DNS 的常見問題和最佳做法。
Pod 的 dnsConfig 搜尋網域數量上限
Kubernetes 將 DNS 搜尋網域數量限制為 32 個。如果您嘗試在 Pod 的 dnsConfig 中定義超過 32 個搜尋網域,kube-apiserver 就不會建立 Pod,並顯示類似下列內容的錯誤訊息:
The Pod "dns-example" is invalid: spec.dnsConfig.searches: Invalid value: []string{"ns1.svc.cluster-domain.example", "my.dns.search.suffix1", "ns2.svc.cluster-domain.example", "my.dns.search.suffix2", "ns3.svc.cluster-domain.example", "my.dns.search.suffix3", "ns4.svc.cluster-domain.example", "my.dns.search.suffix4", "ns5.svc.cluster-domain.example", "my.dns.search.suffix5", "ns6.svc.cluster-domain.example", "my.dns.search.suffix6", "ns7.svc.cluster-domain.example", "my.dns.search.suffix7", "ns8.svc.cluster-domain.example", "my.dns.search.suffix8", "ns9.svc.cluster-domain.example", "my.dns.search.suffix9", "ns10.svc.cluster-domain.example", "my.dns.search.suffix10", "ns11.svc.cluster-domain.example", "my.dns.search.suffix11", "ns12.svc.cluster-domain.example", "my.dns.search.suffix12", "ns13.svc.cluster-domain.example", "my.dns.search.suffix13", "ns14.svc.cluster-domain.example", "my.dns.search.suffix14", "ns15.svc.cluster-domain.example", "my.dns.search.suffix15", "ns16.svc.cluster-domain.example", "my.dns.search.suffix16", "my.dns.search.suffix17"}: must not have more than 32 search paths.
kube-apiserver 會在嘗試建立 Pod 時傳回這則錯誤訊息。如要解決這個問題,請從設定中移除額外的搜尋路徑。
kube-dns的上傳nameservers限制
kube-dns 會將 upstreamNameservers 值限制為三個。如果定義超過三個,Cloud Logging 會顯示類似下列內容的錯誤:
Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update
在這種情況下,kube-dns 會忽略 upstreamNameservers 設定,並繼續使用先前的有效設定。如要解決這個問題,請從 kube-dns ConfigMap 中移除多餘的 upstreamNameservers。
擴充 kube-dns
在標準叢集中,您可以將 nodesPerReplica 值調低,以便在叢集節點擴充時建立更多 kube-dns Pod。強烈建議您為 max 欄位設定明確值,確保 Kubernetes API 監控的 kube-dns Pod 數量過多時,GKE 控制平面虛擬機器 (VM) 不會不堪負荷。
您可以將 max 欄位的值設為叢集中的節點數。如果叢集有超過 500 個節點,請將 max 欄位的值設為 500。
如要修改 kube-dns 副本數量,請編輯 kube-dns-autoscaler ConfigMap。
kubectl edit configmap kube-dns-autoscaler --namespace=kube-system
輸出結果會與下列內容相似:
linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'
kube-dns 副本數量的計算公式如下:
replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) )
如要擴大範圍,請將 nodesPerReplica 欄位的值改為較小的值,並加入 max 欄位的值。
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'
這項設定會為叢集中的每八個節點建立一個 kube-dns Pod。24 節點叢集有三個副本,40 節點叢集則有五個副本。如果叢集節點超過 120 個,kube-dns 副本數不會超過 15,也就是 max 欄位的值。
為確保叢集中的 DNS 達到基本可用性,請為 kube-dns 欄位設定最少副本數。
設定 min 欄位後,kube-dns-autoscaler ConfigMap 的輸出內容會與下列內容類似:
linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'
縮短 DNS 查詢時間
使用預設 kube-dns 供應商時,DNS 查詢或 DNS 解析失敗可能會導致延遲時間過長。應用程式可能會將這些問題視為 getaddrinfo EAI_AGAIN 錯誤,表示名稱解析暫時失敗。可能原因如下:
- 工作負載內頻繁的 DNS 查詢。
- 每個節點的 Pod 密度過高。
- 在 Spot VM 或先占 VM 上執行
kube-dns,這可能會導致節點遭到意外刪除。 - 查詢量過高,超出
kube-dnsPod 中dnsmasq執行個體的容量。在 GKE 1.31 以上版本中,單一kube-dns執行個體最多可有 200 個並行 TCP 連線;在 GKE 1.30 以下版本中,最多可有 20 個並行 TCP 連線。
如要縮短 DNS 查詢時間,請採取下列做法:
- 請避免在 Spot VM 或先占 VM 上執行
kube-dns等重要系統元件。建立至少一個具有標準 VM,且沒有 Spot VM 或先占 VM 的節點集區。使用汙點和容許度,確保重要工作負載排程在這些可靠節點上。 - 啟用 NodeLocal DNSCache。NodeLocal DNSCache 會直接在每個節點上快取 DNS 回應,藉此縮短延遲時間,並降低
kube-dns服務的負載。如果您啟用 NodeLocal DNSCache 並使用含有預設拒絕規則的網路政策,請新增政策,允許工作負載將 DNS 查詢傳送至node-local-dnsPod。 - 擴充
kube-dns。 - 請確保應用程式使用
dns.resolve*型函式,而非dns.lookup型函式,因為dns.lookup是同步的。 - 請使用完整網域名稱 (FQDN),例如
https://google.com./,而非https://google.com/。
由於控制層元件 (包括 kube-dns) 會同步升級,因此 GKE 叢集升級期間可能會發生 DNS 解析失敗的情況。這類故障通常只會影響一小部分的節點。在非正式環境中徹底測試叢集升級,確認無誤後再套用至正式叢集。
確保服務可探索性
kube-dns 只會為有 Endpoints 的服務建立 DNS 記錄。如果 Service 沒有任何 Endpoints,kube-dns 就不會為該 Service 建立 DNS 記錄。
管理 DNS TTL 差異
如果 kube-dns 從上游 DNS 解析器收到 DNS 回應,且該回應的 TTL 較長或無限期,就會保留這個 TTL 值。這可能會導致快取項目與實際 IP 位址不一致。
GKE 會在特定控制層版本中解決這個問題,例如 1.21.14-gke.9100 以上版本,或 1.22.15-gke.2100 以上版本。這些版本會將任何存留時間較高的 DNS 回應,存留時間上限值設為 30 秒。這項行為與 NodeLocal DNSCache 類似。
查看 kube-dns 指標
您可以直接從 kube-dnsPod 擷取叢集中 DNS 查詢的指標。
在
kube-system命名空間中尋找kube-dnsPod:kubectl get pods -n kube-system --selector=k8s-app=kube-dns輸出結果會與下列內容相似:
NAME READY STATUS RESTARTS AGE kube-dns-548976df6c-98fkd 4/4 Running 0 48m kube-dns-548976df6c-x4xsh 4/4 Running 0 47m選擇其中一個 Pod,並設定通訊埠轉送,從該 Pod 存取指標:
- 通訊埠
10055會公開kube-dns指標。 - 通訊埠
10054會公開dnsmasq指標。
將
POD_NAME替換為您選擇的 Pod 名稱。POD_NAME="kube-dns-548976df6c-98fkd" # Replace with your pod name kubectl port-forward pod/${POD_NAME} -n kube-system 10055:10055 10054:10054輸出結果會與下列內容相似:
Forwarding from 127.0.0.1:10054 -> 10054 Forwarding from 127.0.0.1:10055 -> 10055- 通訊埠
在新的終端機工作階段中,使用
curl指令存取指標端點。# Get kube-dns metrics curl http://127.0.0.1:10055/metrics # Get dnsmasq metrics curl http://127.0.0.1:10054/metrics畫面中會顯示如下的輸出結果:
kubedns_dnsmasq_errors 0 kubedns_dnsmasq_evictions 0 kubedns_dnsmasq_hits 3.67351e+06 kubedns_dnsmasq_insertions 254114 kubedns_dnsmasq_max_size 1000 kubedns_dnsmasq_misses 3.278166e+06
後續步驟
- 閱讀 GKE 中叢集 DNS 的總覽。
- 如要瞭解 Kubernetes 叢集如何使用 DNS,請參閱「服務和 Pod 的 DNS」。
- 瞭解如何設定 NodeLocal DNSCache。
- 瞭解如何設定自訂 kube-dns 部署作業。