在 Kubernetes 叢集中使用 NodeLocal DNSCache

特性狀態: Kubernetes v1.18 [stable]

本頁介紹了 Kubernetes 中 NodeLocal DNSCache 功能的概覽。

準備工作

你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議在至少有兩個不是控制平面主機的節點上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 操場之一

要檢查版本,請輸入 kubectl version

介紹

NodeLocal DNSCache 透過在叢集節點上以 DaemonSet 形式執行 DNS 快取代理來提高叢集 DNS 效能。在當前的架構中,“ClusterFirst” DNS 模式下的 Pods 透過 `serviceIP` 訪問 kube-dns 進行 DNS 查詢。這透過 kube-proxy 新增的 iptables 規則轉換為 kube-dns/CoreDNS 端點。透過這種新架構,Pods 將訪問在同一節點上執行的 DNS 快取代理,從而避免 iptables DNAT 規則和連線跟蹤。本地快取代理將查詢 kube-dns 服務,以獲取叢集主機名(預設為“`cluster.local`”字尾)的快取未命中。

動機

  • 在當前的 DNS 架構中,如果本地沒有 kube-dns/CoreDNS 例項,DNS QPS 最高的 Pods 可能需要訪問不同的節點。擁有本地快取將有助於在這些場景中改善延遲。

  • 跳過 iptables DNAT 和連線跟蹤將有助於減少 conntrack 競爭,並避免 UDP DNS 條目填滿 conntrack 表。

  • 從本地快取代理到 kube-dns 服務的連線可以升級為 TCP。TCP conntrack 條目將在連線關閉時移除,而 UDP 條目必須超時(預設的 `nf_conntrack_udp_timeout` 是 30 秒)

  • 將 DNS 查詢從 UDP 升級到 TCP 將減少由於 UDP 資料包丟失和 DNS 超時(通常長達 30 秒,3 次重試 + 10 秒超時)造成的尾部延遲。由於 nodelocal 快取偵聽 UDP DNS 查詢,應用程式無需更改。

  • 節點級別的 DNS 請求的指標和可見性。

  • 負快取可以重新啟用,從而減少對 kube-dns 服務的查詢數量。

架構圖

這是啟用 NodeLocal DNSCache 後 DNS 查詢遵循的路徑

NodeLocal DNSCache flow

NodeLocal DNSCache 流程

此圖片顯示了 NodeLocal DNSCache 如何處理 DNS 查詢。

配置

該功能可以透過以下步驟啟用

  • 準備一個類似於示例 `nodelocaldns.yaml` 的清單,並將其儲存為 `nodelocaldns.yaml`。

  • 如果使用 IPv6,並且 CoreDNS 配置檔案中使用的 IPv6 地址採用“IP:Port”格式,則需要將所有 IPv6 地址用方括號括起來。如果您使用上一點中的示例清單,這將要求您修改配置行 L70,如下所示:“`health [__PILLAR__LOCAL__DNS__]:8080`”

  • 用正確的值替換清單中的變數

    kubedns=`kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}`
    domain=<cluster-domain>
    localdns=<node-local-address>
    

    預設情況下,`<cluster-domain>` 為 "cluster.local"。`<node-local-address>` 是為 NodeLocal DNSCache 選擇的本地監聽 IP 地址。

    • 如果 kube-proxy 在 IPTABLES 模式下執行

      sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml
      

      `__PILLAR__CLUSTER__DNS__` 和 `__PILLAR__UPSTREAM__SERVERS__` 將由 `node-local-dns` Pod 填充。在此模式下,`node-local-dns` Pod 偵聽 kube-dns 服務 IP 和 `<node-local-address>`,因此 Pods 可以使用任一 IP 地址查詢 DNS 記錄。

    • 如果 kube-proxy 在 IPVS 模式下執行

      sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/,__PILLAR__DNS__SERVER__//g; s/__PILLAR__CLUSTER__DNS__/$kubedns/g" nodelocaldns.yaml
      

      在此模式下,`node-local-dns` Pod 僅監聽 `<node-local-address>`。由於用於 IPVS 負載均衡的介面已經使用了 kube-dns 叢集 IP,因此 `node-local-dns` 介面不能繫結該地址。`__PILLAR__UPSTREAM__SERVERS__` 將由 node-local-dns Pod 填充。

  • 執行 `kubectl create -f nodelocaldns.yaml`

  • 如果 kube-proxy 以 IPVS 模式執行,則需要修改 kubelet 的 `--cluster-dns` 標誌,使其使用 NodeLocal DNSCache 正在監聽的 `<node-local-address>`。否則,無需修改 `--cluster-dns` 標誌的值,因為 NodeLocal DNSCache 同時監聽 kube-dns 服務 IP 和 `<node-local-address>`。

啟用後,`node-local-dns` Pods 將在叢集中每個節點的 `kube-system` 名稱空間中執行。此 Pod 在快取模式下執行 CoreDNS,因此 CoreDNS 不同外掛暴露的所有指標都將按節點提供。

您可以透過使用 `kubectl delete -f <manifest>` 刪除 DaemonSet 來停用此功能。您還應該還原對 kubelet 配置所做的任何更改。

StubDomains 和上游伺服器配置

在 `kube-system` 名稱空間中的 `kube-dns` ConfigMap 中指定的 StubDomains 和上游伺服器會自動被 `node-local-dns` Pods 識別。ConfigMap 的內容需要遵循 示例 中所示的格式。`node-local-dns` ConfigMap 也可以直接以 Corefile 格式修改 StubDomain 配置。一些雲提供商可能不允許直接修改 `node-local-dns` ConfigMap。在這種情況下,可以更新 `kube-dns` ConfigMap。

設定記憶體限制

`node-local-dns` Pods 使用記憶體來儲存快取條目和處理查詢。由於它們不監視 Kubernetes 物件,因此叢集大小或服務/端點切片數量不會直接影響記憶體使用。記憶體使用量受 DNS 查詢模式的影響。根據 CoreDNS 文件

預設快取大小為 10000 個條目,完全填滿時佔用約 30 MB 記憶體。

這將是每個伺服器塊的記憶體使用量(如果快取完全填滿)。透過指定更小的快取大小可以減少記憶體使用。

併發查詢的數量與記憶體需求相關,因為用於處理查詢的每個額外協程都需要一定量的記憶體。您可以使用 forward 外掛中的 `max_concurrent` 選項設定上限。

如果 `node-local-dns` Pod 嘗試使用超出可用記憶體的量(由於總系統資源,或由於配置的 資源限制),作業系統可能會關閉該 Pod 的容器。如果發生這種情況,被終止的容器(“OOMKilled”)不會清理其在啟動期間新增的自定義包過濾規則。`node-local-dns` 容器應該重新啟動(因為它作為 DaemonSet 的一部分進行管理),但這將導致每次容器失敗時短暫的 DNS 停機:包過濾規則將 DNS 查詢定向到一個不健康的本地 Pod。

您可以透過在不設定限制的情況下執行 node-local-dns Pod 並測量峰值使用量來確定合適的記憶體限制。您也可以以“推薦模式”設定並使用 VerticalPodAutoscaler,然後檢查其推薦值。

上次修改於 2025 年 1 月 16 日太平洋標準時間下午 4:14:修復 nodelocaldns.md 中的 md 格式 (2cb6686fc4)