📢 [文章新增公告] 新增 為 Kubernetes 而生的 GitOps 工具 - ArgoCD 介紹與說明統一機密、身份與加密的管理系統 - HashiCorp Vault 介紹與說明 文章,歡迎點擊前方連結前往查看 💙
目前 Blog 頁籤支援折疊側邊欄功能,在閱讀文章會更方便,歡迎多加利用 💪
GKE DNS 使用 Cloud DNS 運作測試

GKE DNS 使用 Cloud DNS 運作測試

發布於 2025-08-06 · 最後更新於 2025-10-21

最近在評估要將公司內的 EndPoint 都改成 Cloud DNS 的 Private Zone (打造內部的 internal dns 服務機制),到時候 DNS 解析的請求會比以往還要多,所以需要先測試評估 GKE 內的 DNS 解析方案,避免再次發生 Pod 出現 cURL error 6: Could not resolve host,此篇文章測試的是: Cloud DNS 的運作。


首先,先建立一個 dns-test pod 程式連結 以及 nginx 的 pod + svc 程式連結,會分別測試

  1. 叢集內部 cluster.local (nginx-svc.default.svc.cluster.local)

  2. internal-dns 使用 cloud dns private (aaa.test-audit.com)

  3. 外部 dns (ifconfig.me)

並使用 nslookup 腳本進行確認回傳 DNS 解析,每一次測試都會重新建立 KubeDNS Pod

相關程式以及 Prometheus、Grafana 的設定可以參考:https://github.com/880831ian/gke-dns


在建立完 Cluster 後,可以先觀察在 Cloud DNS 是否新增的 Private Zone



由於裡面有很多的 Record,我們先搜尋下面會用到的 nginx-svc.default.svc.cluster.local 來當作範例


叢集內部 cluster.local

一樣會觀察 KubeDNS Pod Metrics,因為就算開啟 Cloud DNS 後,KubeDNS 還是會留著


https://cloud.google.com/kubernetes-engine/docs/how-to/cloud-dns?hl=zh-tw#architecture

https://cloud.google.com/kubernetes-engine/docs/how-to/cloud-dns?hl=zh-tw#architecture


  • 相關 Prometheus 監控指標:
kubedns_dnsmasq_hits{job="kubedns-dns"}
kubedns_dnsmasq_misses{job="kubedns-dns"}

測試腳本:

#!/bin/bash

get_taiwan_time() {
  # 獲取當前 UTC 時間的 Unix 時間戳
  UTC_TIMESTAMP=$(date -u +%s)
  # 加上 8 小時 (台灣時間是 UTC+8)
  TAIPEI_TIMESTAMP=$((UTC_TIMESTAMP + 28800))
  # 將時間戳轉換為格式化後的日期時間
  date -d "@$TAIPEI_TIMESTAMP" "+%Y-%m-%d %H:%M:%S"
}

DOMAIN="nginx-svc.default.svc.cluster.local"
EXPECTED_IP="10.36.16.243"
START_TIME=$(get_taiwan_time)
COUNT=10000
SUCCESS_COUNT=0
FAIL_COUNT=0

echo "== NSLOOKUP TEST START: $START_TIME ==" | tee -a nslookup_full.log

for i in $(seq 1 "$COUNT"); do
  OUTPUT=$(nslookup "$DOMAIN" 2>&1)
  ADDR_LINE=$(echo "$OUTPUT" | grep -E '^Address:')
  if [[ "$ADDR_LINE" == *"$EXPECTED_IP"* ]]; then
    SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  else
    FAIL_COUNT=$((FAIL_COUNT + 1))
  fi

  echo "[$i] === $(get_taiwan_time) 成功: $SUCCESS_COUNT 失敗: $FAIL_COUNT"
done

END_TIME=$(get_taiwan_time)

echo "== NSLOOKUP TEST END: $END_TIME ==" | tee -a nslookup_full.log
echo "成功次數: $SUCCESS_COUNT" | tee -a nslookup_full.log
echo "失敗次數: $FAIL_COUNT" | tee -a nslookup_full.log

10.36.16.243 是 nginx-svc Cluster IP

需要先確認 nginx-svc 的 IP 是多少,然後修改腳本中的 EXPECTED_IP 變數。


測試腳本

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

因為改用 Cloud DNS,所以 KubeDNS 的 hit 沒有往上衝高


模擬 KubeDNS Pod 異常

接下來會在測試中,將 KubeDNS 調整到 0 顆,再開回去,觀察此模式對於 KubeDNS 的依賴

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

大約在 2000 筆請求時左右將 KubeDNS 關成 0 顆,可以發現解析還是正常,代表使用 Cloud DNS 後,KubeDNS 對於叢集內部解析不會有影響


Internal DNS (Cloud DNS Private)

先建立一個 cloud dns private,以下範例是 aaa.test-audit.com > 10.1.1.4,並將此 use VPC 與 GKE 的 VPC 打通


設定 cloud dns private

設定 cloud dns private


  • 相關 Prometheus 監控指標:
kubedns_dnsmasq_hits{job="kubedns-dns"}
kubedns_dnsmasq_misses{job="kubedns-dns"}

測試腳本:

#!/bin/bash

get_taiwan_time() {
  # 獲取當前 UTC 時間的 Unix 時間戳
  UTC_TIMESTAMP=$(date -u +%s)
  # 加上 8 小時 (台灣時間是 UTC+8)
  TAIPEI_TIMESTAMP=$((UTC_TIMESTAMP + 28800))
  # 將時間戳轉換為格式化後的日期時間
  date -d "@$TAIPEI_TIMESTAMP" "+%Y-%m-%d %H:%M:%S"
}

DOMAIN="aaa.test-audit.com"
EXPECTED_IP="10.1.1.4"
START_TIME=$(get_taiwan_time)
COUNT=10000
SUCCESS_COUNT=0
FAIL_COUNT=0

echo "== NSLOOKUP TEST START: $START_TIME ==" | tee -a nslookup_full.log

for i in $(seq 1 "$COUNT"); do
  OUTPUT=$(nslookup "$DOMAIN" 2>&1)
  ADDR_LINE=$(echo "$OUTPUT" | grep -E '^Address:')
  if [[ "$ADDR_LINE" == *"$EXPECTED_IP"* ]]; then
    SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  else
    FAIL_COUNT=$((FAIL_COUNT + 1))
  fi

  echo "[$i] === $(get_taiwan_time) 成功: $SUCCESS_COUNT 失敗: $FAIL_COUNT"
done

END_TIME=$(get_taiwan_time)

echo "== NSLOOKUP TEST END: $END_TIME ==" | tee -a nslookup_full.log
echo "成功次數: $SUCCESS_COUNT" | tee -a nslookup_full.log
echo "失敗次數: $FAIL_COUNT" | tee -a nslookup_full.log

10.1.1.4 是隨機亂取的 IP,只是為了確認 domain 是否能夠正常解析


測試腳本

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

因為改用 Cloud DNS,所以 KubeDNS 的 hit 沒有往上衝高


模擬 KubeDNS Pod 異常

接下來會在測試中,將 KubeDNS 調整到 0 顆,再開回去,觀察此模式對於 KubeDNS 的依賴

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

大約在 2000 筆請求時左右將 KubeDNS 關成 0 顆,可以發現解析還是正常,代表使用 Cloud DNS 後,KubeDNS 對於 internal-dns 解析不會有影響


外部 DNS (ifconfig.me)


  • 相關 Prometheus 監控指標:
kubedns_dnsmasq_hits{job="kubedns-dns"}
kubedns_dnsmasq_misses{job="kubedns-dns"}

測試腳本:

#!/bin/bash

get_taiwan_time() {
  # 獲取當前 UTC 時間的 Unix 時間戳
  UTC_TIMESTAMP=$(date -u +%s)
  # 加上 8 小時 (台灣時間是 UTC+8)
  TAIPEI_TIMESTAMP=$((UTC_TIMESTAMP + 28800))
  # 將時間戳轉換為格式化後的日期時間
  date -d "@$TAIPEI_TIMESTAMP" "+%Y-%m-%d %H:%M:%S"
}

DOMAIN="ifconfig.me"
EXPECTED_IP="34.160.111.145"
START_TIME=$(get_taiwan_time)
COUNT=10000
SUCCESS_COUNT=0
FAIL_COUNT=0

echo "== NSLOOKUP TEST START: $START_TIME ==" | tee -a nslookup_full.log

for i in $(seq 1 "$COUNT"); do
  OUTPUT=$(nslookup "$DOMAIN" 2>&1)
  ADDR_LINE=$(echo "$OUTPUT" | grep -E '^Address:')
  if [[ "$ADDR_LINE" == *"$EXPECTED_IP"* ]]; then
    SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
  else
    FAIL_COUNT=$((FAIL_COUNT + 1))
  fi

  echo "[$i] === $(get_taiwan_time) 成功: $SUCCESS_COUNT 失敗: $FAIL_COUNT"
done

END_TIME=$(get_taiwan_time)

echo "== NSLOOKUP TEST END: $END_TIME ==" | tee -a nslookup_full.log
echo "成功次數: $SUCCESS_COUNT" | tee -a nslookup_full.log
echo "失敗次數: $FAIL_COUNT" | tee -a nslookup_full.log

34.160.111.145 是 ifconfig.me 的 IP,只是為了確認 domain 是否能夠正常解析


測試腳本

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

因為改用 Cloud DNS,所以 KubeDNS 的 hit 沒有往上衝高


模擬 KubeDNS Pod 異常

接下來會在測試中,將 KubeDNS 調整到 0 顆,再開回去,觀察此模式對於 KubeDNS 的依賴

測試結果:


測試結果

測試結果


Prometheus 監控指標

Prometheus 監控指標


結論

大約在 2000 筆請求時左右將 KubeDNS 關成 0 顆,可以發現解析還是正常,代表使用 Cloud DNS 後,KubeDNS 對於外部 DNS解析不會有影響


k6 測試

額外在另一個 cluster 建立 nginx deployment 開 5 個 pod 以及 svc 改成 lb (L4),然後在 cloud dns 的 test-audit-com 設定 nginx-lb-internal.test-audit.com 解析到內網的 svc (10.156.16.16)


使用 k6 測試 kube dns 模式下 IP 跟 DNS 的差異

相關程式可以參考:https://github.com/880831ian/gke-dns

這邊測試的 Node 是用 e2-medium 而非 c3d-standard-4


第一次測試

IP (avg=179.06ms / 3479 RPS)、DNS (avg=191.56ms / 3348 RPS)


IP 第一次測試

IP 第一次測試

DNS 第一次測試

DNS 第一次測試


第二次測試

IP (avg=193.67ms / 3322 RPS)、DNS (avg=302.73ms / 2430 RPS)


IP 第二次測試

IP 第二次測試

DNS 第二次測試

DNS 第二次測試


第三次測試

IP (avg=174.94ms / 3529 RPS)、DNS (avg=253.71ms / 2761 RPS)


IP 第三次測試

IP 第三次測試

DNS 第三次測試

DNS 第三次測試


第四次測試

IP (avg=227.56ms / 2971 RPS)、DNS (avg=316.07ms / 2361 RPS)


IP 第四次測試

IP 第四次測試

DNS 第四次測試

DNS 第四次測試


結論

有發現之前在 KubeDNS 跟 KubeDNS + NodeLocal DNSCache 會有 DNS RPS 大於 IP 的情況,但使用 Cloud DNS 後則沒有發生,推測是因為。Cloud DNS 在 Cluster 外部,所以會比較慢


結論

可以發現,使用 Cloud DNS 的模式下,所有的 DNS 解析都會依靠 Cloud DNS,不會使用到 KubeDNS,所以可以把 KubeDNS 關成 0 顆,避免浪費資源。


GKE Cloud DNS

GKE Cloud DNS


由於官方流程圖有些細節沒有揭露的完成,我們有額外詢問 Google TAM,並畫出以下流程圖,Google TAM 也確認流程正確


自己重新畫的 GKE Cloud DNS

自己重新畫的 GKE Cloud DNS


以下是我們與 Google 討論的內容:

我們:

  1. 圖中粉紅框所選取的兩個 Cloud DNS<Cloud DNS & Cloud DNS (Data Plane)> 在實際的架構中,是兩個獨立的物件嗎?或者其實是同一個物件?

  2. 承(1),以下項目所述的理解是否正確?若有差異的部分請協助說明:目前我們的認知是,在 Internal DNS 上會有三個 Cloud DNS:

    1. GKE 的設定改用 Cloud DNS 的 provider,此時系統會協助我們建立一個 Cloud DNS (Data Plane)。
    2. 我們會自己建立一個 Cloud DNS(Private) For 我們內部自己要用的 Internal DNS。
    3. 進行外部 DNS 解析時,目前的理解是會從 metadata server 對 Cloud DNS 轉送解析需求,是否屬實?
  3. 完成解析後,Cache 的部分是否在 metadata server 裡面進行?

Google:

  1. 處理 private zone 和公有網域名稱的是不同物件,但都在 GCE DNS 服務裡

    1. 主要是建立 cluster-scoped private zone,進到 metadata server 後的行為與原本相同、2 跟 3 正確
  2. 是,除了metadata server 外,同時也會在 GCE DNS 服務裡快取


另外也可以從官方文件中得知 KubeDNS 的 /etc/resolv.conf 設定值,可以知道 Pod 最開始使用的 DNS 解析 Server 是誰。

/etc/resolv.conf 設定值 服務探索和 DNS /etc/resolv.conf

/etc/resolv.conf 設定值 服務探索和 DNS /etc/resolv.conf


實際查看 /etc/resolv.conf

實際查看 /etc/resolv.conf


參考資料

使用 GKE 適用的 Cloud DNS:https://cloud.google.com/kubernetes-engine/docs/how-to/cloud-dns?hl=zh-tw