設定 NodeLocal DNSCache


本頁說明如何使用 NodeLocal DNSCache,縮短 Google Kubernetes Engine (GKE) 叢集中的 DNS 查詢延遲時間。

如為 GKE Autopilot 叢集,NodeLocal DNSCache 預設為啟用,且無法覆寫。

架構

NodeLocal DNSCache 是 GKE 外掛程式,可與 kube-dns 一併執行。

GKE 會將 NodeLocal DNSCache 實作為 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 Service 的 IP 位址為 10.0.0.10:53
  • 自訂存根網域或上游名稱伺服器:查詢會直接從 NodeLocal DNSCache Pod 轉送。
  • Cloud DNS:所有其他查詢都會轉送至與查詢來源 Pod 位於相同節點的本機中繼資料伺服器。本機中繼資料伺服器會存取 Cloud DNS。

如前一段所述,這是 DNS 要求的路徑。

在現有叢集上啟用 NodeLocal DNSCache 時,GKE 會根據節點升級程序,重新建立所有執行 GKE 1.15 以上版本的叢集節點。

GKE 重新建立節點後,會自動在節點中新增 addon.gke.io/node-local-dns-ds-ready=true 標籤。您不得手動將這個標籤新增至叢集節點。

NodeLocal DNSCache 的優點

NodeLocal DNSCache 具有下列優點:

  • 縮短平均 DNS 查詢時間
  • 從 Pods 到本機快取的連線不會建立 conntrack 表格項目。這可防止因 conntrack 資料表耗盡和競爭狀況而導致連線中斷和遭到拒絕。
  • 您可以搭配 Cloud DNS for GKE 使用 NodeLocal DNSCache。
  • 外部網址 (未參照叢集資源的網址) 的 DNS 查詢會直接轉送至本機 Cloud DNS 中繼資料伺服器,略過 kube-dns。
  • 本機 DNS 快取會自動擷取「為存根網域新增自訂解析器」一節中指定的存根網域和上游名稱伺服器。

需求條件和限制

  • NodeLocal DNSCache 會耗用叢集每個節點的運算資源。
  • NodeLocal DNSCache 不支援 Windows Server 節點集區。
  • NodeLocal DNSCache 必須搭配 GKE 1.15 以上版本。
  • NodeLocal DNSCache 會使用 TCP 存取 kube-dns Pod。
  • 在 GKE 1.18 以上版本中,NodeLocal DNSCache 會透過 TCP 和 UDP 存取 upstreamServersstubDomains。DNS 伺服器必須可透過 TCP 和 UDP 存取。
  • DNS 記錄的快取時間如下:
    • 記錄的存留時間 (TTL),或 30 秒 (如果 TTL 超過 30 秒)。
    • 如果 DNS 回應為 NXDOMAIN,則為 5 秒。
  • 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 預設為啟用,且無法覆寫。

如果是標準叢集,您可以使用 Google Cloud CLI,在新叢集或現有叢集上啟用 NodeLocal DNSCache。您可以使用 Google Cloud 控制台,在新叢集中啟用 NodeLocal DNSCache。

在新叢集中啟用 NodeLocal DNSCache

gcloud

如要在新叢集中啟用 NodeLocal DNSCache,請使用 --addons 旗標和 NodeLocalDNS 引數:

gcloud container clusters create CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --addons=NodeLocalDNS

更改下列內容:

控制台

如要在新叢集上啟用 NodeLocal DNSCache,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的「Google Kubernetes Engine」頁面。

    前往「Google Kubernetes Engine」

  2. 按一下「標準」旁的「設定」

  3. 視需要設定叢集。

  4. 按一下導覽窗格中的「Networking」(網路)

  5. 在「進階網路選項」部分,選取「啟用 NodeLocal DNSCache」核取方塊。

  6. 點選「建立」

在現有叢集中啟用 NodeLocal DNSCache

如要在現有叢集中啟用 NodeLocal DNSCache,請使用 --update-addons 旗標並加上 NodeLocalDNS=ENABLED 引數:

gcloud container clusters update CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=ENABLED

更改下列內容:

這項變更需要重新建立節點,可能會導致執行中的工作負載中斷。如要瞭解這項特定變更的詳細資料,請在「manual changes that recreate the nodes using a node upgrade strategy and respecting maintenance policies」(手動變更,使用節點升級策略重建節點,並遵守維護政策) 表格中找到對應的資料列。如要進一步瞭解節點更新,請參閱「規劃節點更新中斷」。

確認已啟用 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 \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=DISABLED

更改下列內容:

這項變更需要重新建立節點,可能會導致執行中的工作負載中斷。如要瞭解這項特定變更的詳細資料,請在「manual changes that recreate the nodes using a node upgrade strategy and respecting maintenance policies」(手動變更,使用節點升級策略重建節點,並遵守維護政策) 表格中找到對應的資料列。如要進一步瞭解節點更新,請參閱「規劃節點更新中斷」。

排解 NodeLocal DNSCache 問題

如需診斷 Kubernetes DNS 問題的一般資訊,請參閱「偵錯 DNS 解析」。

NodeLocal DNSCache 不會立即啟用

在現有叢集上啟用 NodeLocal DNSCache 時,如果叢集已設定維護期間或排除時段,GKE 可能不會立即更新節點。詳情請參閱節點重建和維護期間的注意事項

如果不想等待,可以呼叫 gcloud container clusters upgrade 指令並傳遞 --cluster-version 旗標,將節點手動變更為節點集區目前執行的 GKE 版本。如要使用此解決方法,必須使用 Google Cloud CLI。

搭配 Cloud DNS 使用 NodeLocal DNSCache

如果您搭配使用 NodeLocal DNSCache 和 Cloud DNS,叢集會使用名稱伺服器 IP 位址 169.254.20.10,如下圖所示:

採用 Cloud DNS 架構的 NodeLocal DNSCache。

因此,kube-dns 服務的 IP 位址可能與 Pod 使用的名稱伺服器 IP 位址不同。這是預期行為,因為 Cloud DNS 必須使用 169.254.20.10 名稱伺服器 IP 位址,才能正常運作。

如要檢查 IP 位址,請執行下列指令:

  1. 查看 kube-dns Service 的 IP 位址:

    kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
    

    輸出內容是 kube-dns 的 IP 位址,例如 10.0.0.10:53

  2. 在 Pod 中開啟殼層工作階段:

    kubectl exec -it POD_NAME -- /bin/bash
    
  3. 在 Pod Shell 工作階段中,讀取 /etc/resolv.conf 檔案的內容:

    cat /etc/resolv.conf
    

    輸出內容為 169.254.20.10

搭配 NodeLocal DNSCache 使用的網路政策

如果您使用 NodeLocal DNSCache 搭配網路政策,且未使用 Cloud DNSGKE 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 的叢集上,如果 Pod 的 hostNetwork 設為 true,且 dnsPolicy 設為 ClusterFirstWithHostNet,就無法連線至叢集 DNS 後端。DNS 記錄可能包含類似下列內容的項目:

nslookup: write to 'a.b.c.d': Operation not permitted

;; connection timed out; no servers could be reached

輸出內容表示 DNS 要求無法連上後端伺服器。

解決方法是為 hostNetwork Pod 設定 dnsPolicydnsConfig

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"

更改下列內容:

  • NAMESPACEhostNetwork 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 Cluster IP 服務的 IP 位址。在本例中,kube-dns 未在 2 秒內收到 DNS 要求的回應。可能原因如下:

  • 網路連線問題。
  • 工作負載的 DNS 查詢量大幅增加,或因節點集區擴充而增加。

因此,現有的 kube-dns Pod 無法及時處理所有要求。解決方法是調整自動調度資源參數,增加 kube-dns 副本數量。

擴充 kube-dns

您可以調低「nodesPerReplica」的值,確保在叢集節點擴充時,系統會建立更多 kube-dns Pod。強烈建議您設定明確的 max 值,確保 GKE 控制層虛擬機器 (VM) 不會因大量 kube-dns Pod 監控 Kubernetes API 而不堪負荷。

您可以將 max 設為叢集中的節點數。如果叢集的節點超過 500 個,請將 max 設為 500。

如果是標準叢集,您可以編輯 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 副本數量是使用下列公式計算而得:

replicas = 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 設定備用資源數量下限。

kube-dns-autoscaler ConfigMap 輸出內容 (含 min 欄位) 應如下所示:

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'

後續步驟