排解 GKE 中的 Cloud DNS 問題

如果 Pod 無法連線至服務,且 Google Kubernetes Engine (GKE) 叢集使用 Cloud DNS 做為 DNS 供應商,您可能會遇到 dial tcp: i/o timeout 或 no such host 等錯誤。這類錯誤通常表示 Cloud DNS 設定有問題,例如私人區域設定錯誤或 Cloud DNS 範圍不正確。

本頁面說明如何診斷及解決使用 GKE 代管型 Cloud DNS 服務時的常見問題,確保工作負載的 DNS 解析作業穩定可靠。

平台管理員和營運人員,以及設定及管理 GKE 和 Cloud DNS 整合的網路專家,都必須瞭解這項資訊。如果應用程式開發人員遇到服務探索問題,這項工具也很有幫助。如要進一步瞭解我們在 Google Cloud 內容中提及的常見角色和範例工作,請參閱「常見的 GKE 使用者角色和工作」。

找出 Cloud DNS 的 DNS 問題來源

以下各節有助於診斷 Cloud DNS 無法解析查詢的原因。

確認基本設定

如果 Pod 無法解析 DNS 查詢,請確認 Cloud DNS 的設定符合需求。本節將協助您確認是否使用 Cloud DNS、確認 GKE 叢集是否有私人 DNS 區域,以及確保目標服務的 DNS 記錄正確無誤。

如要驗證這些設定,請完成下列指令:

  1. 查看 Pod 使用的 DNS 伺服器:

    kubectl exec -it POD_NAME -- cat /etc/resolv.conf | grep nameserver
    

    將 POD_NAME 替換為 DNS 解析發生問題的 Pod 名稱。

    如果您使用的是 Cloud DNS,輸出內容如下:

    nameserver 169.254.169.254
    

    如果看到其他值,表示您並未使用 Cloud DNS。確認 Cloud DNS 已正確啟用。

  2. 確認受管理區域是否存在:

    gcloud dns managed-zones list --format list
    

    輸出結果會與下列內容相似:

    - creationTime: 2021-02-12T19:24:37.045Z
      description: Private zone for GKE cluster "" with cluster suffix "CLUSTER_DOMAIN" in project "PROJECT_ID"
      dnsName: CLUSTER_DOMAIN.
      id: 5887499284756055830
      kind: dns#managedZone
      name: gke-CLUSTER_NAME-aa94c1f9-dns
      nameServers: ['ns-gcp-private.googledomains.com.']
      privateVisibilityConfig: {'kind': 'dns#managedZonePrivateVisibilityConfig'}
      visibility: private
    

    這項輸出內容包含下列值:

    • CLUSTER_DOMAIN:系統自動指派給叢集的 DNS 網域字尾。
    • PROJECT_ID:您的專案 ID。
    • CLUSTER_NAME:具有私人區域的叢集名稱。

    在這個輸出內容中,「name」欄位的值顯示Google Cloud 已建立名為 gke-CLUSTER_NAME-aa94c1f9-dns 的區域。

    如果沒有看到代管區域,表示叢集未建立私人區域,或您可能未正確通過驗證。如要排解問題,請參閱 Cloud DNS 說明文件中的「私人區域」。

  3. 驗證服務的 DNS 記錄:

    gcloud dns record-sets list --zone ZONE_NAME | grep SERVICE_NAME
    

    更改下列內容:

    • ZONE_NAME:私人區域的名稱。
    • SERVICE_NAME:Service 的名稱。

    輸出內容大致如下:

    dns-test.default.svc.cluster.local.                A     30     10.47.255.11
    

    這項輸出內容顯示 Cloud DNS 包含網域 dns-test.default.svc.cluster.local. 的 A 記錄,且叢集的 IP 位址為 10.47.255.11。

    如果記錄有誤,請參閱 Cloud DNS 說明文件中的「修補資源記錄集」,更新記錄。

驗證回應政策

確認回應政策存在且名稱正確:

  1. 查看所有回應政策的清單:

    gcloud dns response-policies list --format="table(responsePolicyName, description)"
    

    輸出結果會與下列內容相似:

    RESPONSE_POLICY_NAME          DESCRIPTION
    gke-CLUSTER_NAME-52c8f518-rp  Response Policy for GKE cluster "CLUSTER_NAME" with cluster suffix "cluster.local." in project "gke-dev" with scope "CLUSTER_SCOPE".
    

    在這個輸出內容中,gke-CLUSTER_NAME-52c8f518-rp 表示Google Cloud 建立名為 gke-CLUSTER_NAME-aa94c1f9-rp 的私人區域。Google Cloud 建立的回應政策會加上 gke- 前置字元。

  2. 查看特定私人區域中的回應政策:

    gcloud dns response-policies rules list ZONE_NAME \
        --format="table(localData.localDatas[0].name, localData.localDatas[0].rrdatas[0])"
    

    將 ZONE_NAME 替換為發生問題的私人區域名稱。

    輸出結果會與下列內容相似:

    1.240.27.10.in-addr.arpa.    kubernetes.default.svc.cluster.local.
    52.252.27.10.in-addr.arpa.   default-http-backend.kube-system.svc.cluster.local.
    10.240.27.10.in-addr.arpa.   kube-dns.kube-system.svc.cluster.local.
    146.250.27.10.in-addr.arpa.  metrics-server.kube-system.svc.cluster.local.
    

    第一欄會顯示規則比對的 IP 位址或網域名稱模式。第二欄是與 IP 位址相關聯的主機名稱。

如果發現這些指令的輸出內容有任何問題,請參閱 Cloud DNS 說明文件中的「更新回應政策規則」一節。

使用記錄、資訊主頁和指標進行調查

Cloud DNS 提供多種記錄和監控選項,協助您進一步調查 DNS 問題:

查看是否有新記錄

查看記錄,確認代管 Cloud DNS 私人區域中是否建立任何新記錄。如果叢集突然發生 DNS 解析失敗的情況,這項功能就很有幫助。

如要檢查是否有新記錄,請完成下列步驟:

  1. 前往 Google Cloud 控制台的「Logs Explorer」頁面。

    前往 Logs Explorer

  2. 在查詢窗格中,輸入下列查詢:

    resource.type="dns_managed_zone"
    protoPayload.request.change.additions.name="headless-svc-stateful.default.svc.cluster.local."
    protoPayload.methodName="dns.changes.create"
    
  3. 點選「執行查詢」。

  4. 查看輸出內容。如果發現變更與您首次注意到錯誤的時間相符,請考慮還原這些變更。

驗證自訂虛設常式網域和名稱伺服器

如果您使用 GKE Standard 叢集,並搭配自訂存根網域或上游名稱伺服器,請檢查 ConfigMap 並確認值是否正確。

Cloud DNS 會將 stubDomains 和 upstreamNameservers 值轉換為 Cloud DNS 轉送區域。這些資源由 Google 管理,因此如果發現任何錯誤,請與 Cloud Customer Care 團隊聯絡,尋求協助。

與 Cloud Customer Care 團隊聯絡

如果已完成上述各節的步驟,但仍無法診斷問題原因,請與 Cloud Customer Care 團隊聯絡。

解決特定錯誤

如果遇到特定錯誤或問題,請參考下列各節的建議。

問題:無法從 Compute Engine VM 解析 GKE 叢集 Service

如果無法從 Compute Engine VM 解析 GKE 叢集服務,請確認叢集的 Cloud DNS 範圍。

您在 Cloud DNS 中使用的範圍會決定可解析的資源:

  • 叢集範圍:DNS 解析僅限於 Kubernetes 叢集「內」的資源 (Pod 和服務)。這是預設設定,如果您不需要解析 Kubernetes 叢集或 GKE 虛擬私有雲 (VPC) 外部的資源,就適合使用這項設定。

  • 虛擬私有雲範圍:DNS 解析會擴展到整個虛擬私有雲,包括 Compute Engine VM 等資源。這樣一來,叢集就能解析 GKE 叢集外部,但位於相同虛擬私有雲內資源 (例如 Google Cloud VM) 的內部 DNS 記錄。

如要驗證叢集的 Cloud DNS 範圍,請完成下列步驟:

  1. 前往 Google Cloud 控制台的「Kubernetes clusters」(Kubernetes 叢集) 頁面。

    前往 Kubernetes 叢集

  2. 按一下發生 DNS 問題的叢集名稱。

  3. 在叢集詳細資料頁面的「Cluster networking」(叢集網路) 部分,查看「DNS provider」(DNS 供應商) 列中的資訊。

  4. 如果看到「Cloud DNS (cluster scope)」(Cloud DNS (叢集範圍)),代表您使用的是叢集範圍。如要變更 DNS 範圍,請使用適當的 DNS 範圍重新建立叢集。

問題:啟用 Cloud DNS 後,Pod 仍使用 kube-dns

如果 Pod 在現有叢集啟用 Cloud DNS 後仍使用 kube-dns,請確認您在叢集啟用 Cloud DNS 後,已升級或重新建立節點集區。完成這個步驟前,Pod 會繼續使用 kube-dns。

問題:無法更新現有叢集,或建立已啟用 Cloud DNS 的叢集

請確認您使用的是正確版本。如要使用 Cloud DNS for GKE,叢集必須採用虛擬私有雲範圍,且 GKE 版本為 1.19 以上,或採用叢集範圍,且 GKE 版本為 1.24.7-gke.800、1.25.3-gke.700 以上。

問題:在叢集上啟用 Cloud DNS 後,節點上的 DNS 查詢失敗

如果您在具有自訂存根網域或上游名稱伺服器的 GKE 叢集中啟用叢集範圍 Cloud DNS,自訂設定會同時套用至叢集中的節點和 Pod,因為 Cloud DNS 無法區分 Pod 和節點 DNS 要求。如果自訂上游伺服器無法解析查詢,節點上的 DNS 查詢可能會失敗。

問題:無法更新或建立已啟用 Cloud DNS 附加型虛擬私有雲範圍的叢集

請確認您使用的是正確版本。Cloud DNS 附加型虛擬私有雲範圍需要 GKE 1.28 以上版本。

錯誤:Cloud DNS 已停用

停用 Cloud DNS API 時,會發生下列事件:

Warning   FailedPrecondition        service/default-http-backend
Failed to send requests to Cloud DNS: Cloud DNS API Disabled. Please enable the Cloud DNS API in your project PROJECT_NAME: Cloud DNS API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/dns.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.

發生這項錯誤的原因是 Cloud DNS API 預設為停用。您必須手動啟用 Cloud DNS API。

如要解決這個問題,請啟用 Cloud DNS API。

錯誤:無法傳送要求至 Cloud DNS:超出 API 頻率限制。

如果專案超出 Cloud DNS 配額或限制,就會發生下列事件:

kube-system   27s         Warning   InsufficientQuota
managedzone/gke-cluster-quota-ee1bd2ca-dns     Failed to send requests to Cloud DNS: API rate limit exceeded. Contact Google Cloud support team to request a quota increase for your project PROJECT_NAME: Quota exceeded for quota metric 'Write requests' and limit 'Write limit for a minute for a region' of service 'dns.googleapis.com' for consumer 'project_number:PROJECT_NUMBER.

如要解決這個問題,請查看「Cloud DNS 配額」和「Compute Engine 配額與限制」。您可以使用 Google Cloud 控制台提高配額。

錯誤:由於先前發生錯誤,無法將要求傳送至 Cloud DNS

如果錯誤導致連鎖性故障,就會發生下列事件:

kube-system   27s         Warning   InsufficientQuota
managedzone/gke-cluster-quota-ee1bd2ca-dns     Failed to send requests to Cloud DNS: API rate limit exceeded. Contact Google Cloud support team to request a quota increase for your project PROJECT_NAME: Quota exceeded for quota metric 'Write requests' and limit 'Write limit for a minute for a region' of service 'dns.googleapis.com' for consumer 'project_number:PROJECT_NUMBER.
kube-system   27s         Warning   FailedPrecondition               service/default-http-backend                         Failed to send requests to Cloud DNS due to a previous error. Please check the cluster events.

如要解決這個問題,請查看叢集事件,找出原始錯誤的來源,並按照操作說明解決根本問題。

在上述範例中,代管區域的 InsufficientQuota 錯誤觸發了連鎖故障。第二個 FailedPrecondition 錯誤表示先前發生錯誤,也就是初始配額不足的問題。如要解決這個範例問題,請按照 Cloud DNS 配額錯誤的指引操作。

錯誤:無法繫結回應政策

當回應政策繫結至叢集網路,且 Cloud DNS for GKE 嘗試將回應政策繫結至網路時,會發生下列事件:

kube-system   9s          Warning   FailedPrecondition               responsepolicy/gke-2949673445-rp
Failed to bind response policy gke-2949673445-rp to test. Please verify that another Response Policy is not already associated with the network: Network 'https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/global/networks/NETWORK_NAME' cannot be bound to this response policy because it is already bound to another response policy.
kube-system   9s          Warning   FailedPrecondition               service/kube-dns
Failed to send requests to Cloud DNS due to a previous error. Please check the cluster events.

如要解決這個問題,請完成下列步驟:

  1. 取得繫結至網路的回應政策:

    gcloud dns response-policies list --filter='networks.networkUrl: NETWORK_URL'
    

    將 NETWORK_URL 替換為錯誤中的網路網址,例如 https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/NETWORK_NAME。

    如果輸出內容為空白,回應政策可能不在同一個專案中。 請前往下一個步驟,搜尋回應政策。

    如果輸出內容與下列內容相似,請跳至步驟 4,刪除回應政策。

    [
       {
          "description": "Response Policy for GKE cluster \"CLUSTER_NAME\" with cluster suffix \"cluster.local.\" in project \"PROJECT_ID\" with scope \"CLUSTER_SCOPE\".",
          ...
          "kind": "dns#responsePolicy",
          "responsePolicyName": "gke-CLUSTER_NAME-POLICY_ID-rp"
       }
    ]
    
  2. 使用 IAM 政策分析工具,取得具備 dns.networks.bindDNSResponsePolicy 權限的專案清單。

  3. 檢查各項專案是否有繫結至網路的回應政策:

    gcloud dns response-policies list --filter='networks.networkUrl:NETWORK_URL' \
        --project=PROJECT_NAME
    
  4. 刪除回應政策。

錯誤:kube-dns 中指定的設定無效

套用不適用於 GKE Cloud DNS 的自訂 kube-dns ConfigMap 時,會發生下列事件:

kube-system   49s         Warning   FailedValidation                 configmap/kube-dns
Invalid configuration specified in kube-dns: error parsing stubDomains for ConfigMap kube-dns: dnsServer [8.8.8.256] validation: IP address "8.8.8.256" invalid

如要解決這個問題,請查看 ConfigMap 無效部分的錯誤詳細資料。在上述範例中,8.8.8.256 不是有效的 IP 位址。

後續步驟