使用 kube-dns


本頁說明 Google Kubernetes Engine (GKE) 如何使用 kube-dns (GKE 叢集的預設 DNS 提供者) 實作服務探索功能。

如為 Autopilot 叢集,您無法修改預設的 kube-dns 設定。

架構

建立叢集時,GKE 會在 kube-system 命名空間中自動部署 kube-dns Pod。Pod 會透過對應的服務存取 kube-dns 部署,該服務會將 kube-dns Pod 分組,並為這些 Pod 提供單一 IP 位址 (ClusterIP)。根據預設,叢集中的所有 Pod 都會使用這項服務解析 DNS 查詢。下圖顯示 Pod 與 kube-dns 服務之間的關係。

kube-dns Pod 與 kube-dns 服務的關係。

kube-dns 會調度資源,以滿足叢集的 DNS 需求。這項調度作業是由 kube-dns-autoscaler 控制,這個 Pod 預設會部署在所有 GKE 叢集中。kube-dns-autoscaler 會根據叢集中的節點和核心數量,調整 kube-dns Deployment 中的副本數量。

kube-dns 支援每個無標題服務最多 1000 個端點。

如何設定 Pod DNS

在每個節點上執行的 kubelet 會設定 Pod 的 etc/resolv.conf,以使用 kube-dns 服務的 ClusterIP。以下設定範例顯示 kube-dns 服務的 IP 位址為 10.0.0.10。這個 IP 位址在其他叢集中會有所不同。

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

kube-dns 是叢集網域 (cluster.local) 的權威名稱伺服器,會以遞迴方式解析外部名稱。系統會先使用本機搜尋路徑,完成不完全符合資格的簡稱,例如 myservice

為存根網域新增自訂解析器

您可以修改 kube-dns 的 ConfigMap,在叢集內的 DNS 基礎架構中設定虛設常式網域。

存根網域可讓您設定自訂的網域專屬解析器,以便在解析這些網域時,kube-dns 會將 DNS 要求轉送至特定的上游 DNS 伺服器。

以下 kube-dns 的 ConfigMap 資訊清單範例包含 stubDomains 設定,可為網域 example.com 設定自訂解析程式。

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",
        "1.1.1.1",
        "1.0.0.1"
      ]
    }

執行下列指令來開啟文字編輯器:

kubectl edit configmap kube-dns -n kube-system

將檔案內容替換為資訊清單,然後結束文字編輯器,將資訊清單套用至叢集。

上游網域名稱伺服器

如果您修改 kube-dns 的 ConfigMap 以納入 upstreamNameservers,kube-dns 會將 *.cluster.local 以外的所有 DNS 要求轉送至這些伺服器。包括 metadata.internal*.google.internal,上游伺服器無法解析這些項目。

如果您啟用 GKE 適用的工作負載身分聯盟,或任何依賴 metadata.internal 解析的工作負載,請在 ConfigMap 中新增 stubDomain,保留 *.internal 名稱解析。

data:
  stubDomains: |
    {
      "internal": [
        "169.254.169.254"
      ]
    }
  upstreamNameservers: |
    ["8.8.8.8"]

疑難排解

如要瞭解如何排解 kube-dns 問題,請參閱下列頁面:

限制

如要瞭解 kube-dns 的限制,請參閱下列各節。

搜尋網域限制

/etc/resolv.conf 最多可有六個 DNS 搜尋網域。如果定義超過六個搜尋網域,執行 kubectl describe pod 指令時會顯示下列警告:

Search Line limits were exceeded, some search paths have been omitted, the applied search line is: default.svc.cluster.local svc.cluster.local cluster.local c.<project ID>.internal google.internal

這項警告會記錄在容器記錄的 Cloud Logging 區段中。

如要解決這個問題,請從設定中移除額外的搜尋路徑。

請注意 upstreamNameservers 限制

Kubernetes 最多可設定三個 upstreamNameservers 值。如果定義超過三個 upstreamNameservers,您會在 kube-dns 部署記錄的 Cloud Logging 中看到下列錯誤:

Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update

發生這種情況時,kube-dns 的行為就像沒有設定 upstreamNameservers 一樣。如要解決這個問題,請從設定中移除多餘的 upstreamNameservers

kube-dns 的效能限制

如果使用預設的 kube-dns 供應商時,DNS 查詢延遲時間過長或 DNS 解析失敗,可能是因為:

  • 在工作負載中頻繁執行 DNS 查詢
  • 部署每個節點的 Pod 密度較高
  • 超過每個 kube-dns Pod 的每秒查詢次數 (QPS) 上限 (20)。
  • 在 Spot 或先占 VM 上執行 kube-dns,這可能會導致節點意外遭到刪除,進而發生 DNS 解析問題。

如要縮短 DNS 查詢時間,可以選擇下列任一選項:

  • 請避免在 Spot 或先占 VM 上執行 kube-dns 等重要系統元件。使用 Spot VM 或先占 VM 做為 DNS 可能會導致故障,並中斷叢集運作。
  • 最佳做法是建立至少一個由標準 (非 Spot 或先占型) VM 組成的節點集區,用於代管 kube-dns 等重要系統元件。如要確保重要工作負載只會排程到可靠的節點集區,避免在 Spot 或先占 VM 上執行,可以對 Spot VM 使用 taint 和容許條件
  • 啟用 NodeLocal DNSCache
  • 擴充 kube-dns
  • 請確保應用程式使用以 dns.resolve* 為基礎的函式,而非以 dns.lookup 為基礎的函式,因為 dns.lookup 是同步函式。dns.resolve* 函式一律會在網路上執行非同步 DNS 查詢。

服務 DNS 記錄

kube-dns 只會為具有 Endpoints 的服務建立 DNS 記錄。

DNS 上游伺服器的存留時間較長

如果 kube-dns 從上游 DNS 解析器收到 DNS 回應,且 TTL 較大或為「無限」,則會將這個 TTL 值保留在快取中的 DNS 項目。這個項目永遠不會過期,因此可能會造成項目與為 TTL 名稱解析的實際 IP 位址之間出現差異。

GKE 會針對 TTL 高於 30 秒的 DNS 回應,將 TTL 值上限設為 30 秒,藉此解決下列控制層版本中的問題:

  • 1.21.14-gke.9100
  • 1.22.15-gke.2100
  • 1.23.13-gke.500
  • 1.24.7-gke.500
  • 1.25.2-gke.500 以上版本

這項行為與 NodeLocal DNSCache 類似。

記錄 kube-dns 或 dnsmasq 指標

您可以取得 GKE 叢集中的 DNS 查詢相關指標。這是快速取得 kube-dns 或 dnsmasq 指標的方法,不需要修改部署作業。

  1. 列出 kube-dns 部署作業下的 Pod。

    $ 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
    
  2. 選取 Pod 並將其名稱設為變數。

    POD="kube-dns-548976df6c-98fkd"
    
  3. 為所選 kube-dns Pod 設定通訊埠轉送。

    $ kubectl port-forward pod/${POD} -n kube-system 10054:10054 10055:10055
    

    畫面中會顯示如下的輸出結果:

    Forwarding from 127.0.0.1:10054 -> 10054
    Forwarding from 127.0.0.1:10055 -> 10055
    
  4. 在端點上執行下列 curl 指令,即可取得指標。

    $ curl http://127.0.0.1:10054/metrics; curl http://127.0.0.1:10055/metrics

    通訊埠 10054 包含 dnsmasq 指標,通訊埠 10055 則包含 kube-dns 指標。

    畫面中會顯示如下的輸出結果:

    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
    
    

後續步驟