如何對使用 Amazon EKS 時的 DNS 失敗進行疑難排解?

5 分的閱讀內容
0

在我的 Amazon Elastic Kubernetes Service (Amazon EKS) 叢集中使用 CoreDNS 的應用程式或 Pod 會造成內部或外部 DNS 名稱解析失敗。

簡短說明

在 Amazon EKS 叢集內執行的 Pod 使用 CoreDNS 叢集 IP 位址作為名稱伺服器來查詢內部和外部 DNS 記錄。如果 CoreDNS Pod、服務組態或連線發生問題,則應用程式可能無法進行 DNS 解析。

一個名為 kube-dns 的服務物件會提取 CoreDNS Pod。若要對 CoreDNS Pod 的問題進行疑難排解,請驗證所有 kube-dns 服務元件的工作狀態,例如服務端點選項和 iptables 規則。

解決方法

下列解決方法適用於 CoreDNS ClusterIP 10.100.0.10

完成下列步驟:

  1. 取得 CoreDNS 服務的 ClusterIP:

    kubectl get service kube-dns -n kube-system
  2. 確認 DNS 端點已公開並指向 CoreDNS Pod:

    kubectl -n kube-system get endpoints kube-dns

    範例輸出:

    NAME       ENDPOINTS                                                        AGE
    kube-dns   192.168.2.218:53,192.168.3.117:53,192.168.2.218:53 + 1 more...   90d

    **注意:**如果端點清單為空白,請檢查 CoreDNS Pod 的 Pod 狀態

  3. 確認安全群組或網路存取控制清單 (network ACL) 在 Pod 與 CoreDNS 通訊時未封鎖 Pod。

    如需詳細資訊,請參閱為什麼我的 Pod 無法連接到 Amazon EKS 中的其他 Pod?

確認 kube-proxy Pod 是否正常運作

若要確認 kube-proxy Pod 可存取叢集的 API 伺服器,請檢查您的日誌找出控制平面的逾時錯誤。另請檢查 403 未經授權的錯誤。

取得 kube-proxy 日誌:

kubectl logs -n kube-system --selector 'k8s-app=kube-proxy'

**注意:**Kube-proxy 會從控制平面取得端點,並在每個節點上建立 iptables 規則。

檢查發生問題時 CoreDNS 區域的 CPU 使用率

Amazon EKS CoreDNS 附加元件只為 CoreDNS Pod 的記憶體增加 170Mi 限制。CoreDNS 網站不定義 CPU 限制,因此容器可以使用它執行的節點上的所有可用 CPU 資源。如果節點 CPU 使用率達到 100%,則 Amazon EKS 應用程式日誌中可能會出現 DNS 逾時錯誤。這是因為 CoreDNS Pod 沒有足夠的 CPU 資源來處理所有 DNS 查詢。

連線至應用程式 Pod 以疑難排解 DNS 問題

完成下列步驟:

  1. 若要在應用程式 Pod 內執行命令,請執行下列命令以存取執行中 Pod 內的 Shell:

    $ kubectl exec -it your-pod-name -- sh

    如果應用程式 Pod 沒有可用的 Shell 二進位檔,則您會收到類似下列範例的錯誤訊息:

    "OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown command terminated with exit code 126

    若要偵錯,請更新在清單檔案中使用的映像檔以取得其他映像檔,例如 Docker 網站上的 busybox 映像檔。

  2. 確認 kube-dns 服務的叢集 IP 地址是否位於 Pod 站的 /etc/resolv.conf 檔案中。在 Pod 內的 shell 中執行以下命令:

    cat /etc/resolv.conf

    下列範例 resolv.conf 檔案顯示設定為針對 DNS 請求指向 10.100.0.10 的 Pod。IP 地址必須符合您的 kube-dns 服務的 ClusterIP

    nameserver 10.100.0.10
    search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal
    options ndots:5

    **注意:**您可以使用 Pod 規格中的 dnsPolicy 欄位來管理 Pod 的 DNS 組態。如果未填入此欄位,則預設會使用 ClusterFirst DNS 政策。如需 ClusterFirst DNS 政策的詳細資訊,請參閱 Kubernetes 網站上的 Pod 的 DNS 政策

  3. 若要確認您的 Pod 可以使用預設 ClusterIP 來解析內部網域,請在 Pod 內的 Shell 中執行下列命令:

    nslookup kubernetes.default 10.100.0.10

    範例輸出:

    Server:     10.100.0.10
    Address:    10.100.0.10#53
    Name:       kubernetes.default.svc.cluster.local
    Address:    10.100.0.1
  4. 若要確認您的 Pod 可以使用預設 ClusterIP 來解析外部網域,請在 Pod 內的 Shell 中執行下列命令:

    nslookup amazon.com 10.100.0.10

    範例輸出:

    Server:     10.100.0.10
    Address:    10.100.0.10#53
    Non-authoritative answer:
    Name:   amazon.com
    Address: 176.32.98.166
    Name:    amazon.com
    Address: 205.251.242.103
    Name:    amazon.com
    Address: 176.32.103.205
  5. 確認您的網域是否可以使用 CoreDNS Pod的 IP 地址直接解析。在 Pod 內的 shell 中執行下列命令:

    nslookup kubernetes COREDNS_POD_IP
    
    nslookup amazon.com COREDNS_POD_IP

    **注意:**將 COREDNS_POD_IP 取代為 kubectl get 端點中的一個端點 IP 地址。

從 CoreDNS Pod 取得更詳細的日誌以進行偵錯

完成下列步驟:

  1. 開啟 CoreDNS Pod 的偵錯日誌,然後將日誌外掛程式新增至 CoreDNS ConfigMap:

    kubectl -n kube-system edit configmap coredns

    **注意:**如需詳細資訊,請參閱 CoreDNS 網站上的日誌外掛程式

  2. 在輸出中出現的編輯器畫面中,新增日誌字串:

    kind: ConfigMap
    apiVersion: v1
    data:
      Corefile: |
        .:53 {
            log    # Enabling CoreDNS Logging
            errors
            health
            kubernetes cluster.local in-addr.arpa ip6.arpa {
              pods insecure
              upstream
              fallthrough in-addr.arpa ip6.arpa
            }
            ...
    ...

    **注意:**重新載入組態 CoreDNS 需要幾分鐘。若要立即套用變更,請逐一重新啟動 POD。

  3. 檢查 CoreDNS 日誌是否失敗或從應用程序區域中獲得任何點擊:

    kubectl logs --follow -n kube-system --selector 'k8s-app=kube-dns'

更新 ndots 值

ndots 值是在進行初始絕對查詢之前,必須出現在網域名稱中才能解析查詢的點數。

例如,您在非完整網域名稱中將 ndots 選項設定為預設值 5。然後,所有不屬於內部網域 cluster.local 的外部網域都會在查詢之前附加至搜尋網域。

下列範例包含應用程式 Pod 的 /etc/resolv.conf 檔案設定:

nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ec2.internal
options ndots:5

CoreDNS 會在查詢的網域中尋找五個點號。如果 Pod 對 amazon.com 進行 DNS 解析呼叫,則您的日誌看起來會類似下列範例:

[INFO] 192.168.3.71:33238 - 36534 "A IN amazon.com.default.svc.cluster.local. udp 54 false 512" NXDOMAIN qr,aa,rd 147 0.000473434s
[INFO] 192.168.3.71:57098 - 43241 "A IN amazon.com.svc.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000066171s
[INFO] 192.168.3.71:51937 - 15588 "A IN amazon.com.cluster.local. udp 42 false 512" NXDOMAIN qr,aa,rd 135 0.000137489s
[INFO] 192.168.3.71:52618 - 14916 "A IN amazon.com.ec2.internal. udp 41 false 512" NXDOMAIN qr,rd,ra 41 0.001248388s
[INFO] 192.168.3.71:51298 - 65181 "A IN amazon.com. udp 28 false 512" NOERROR qr,rd,ra 106 0.001711104s

**注意:**NXDOMAIN 表示找不到網域記錄,而 NOERROR 表示找到網域記錄。

在最後針對絕對網域進行最終呼叫之前,每個搜尋網域都冠上了 amazon.com。在結尾附加點 (.) 的最終網域名稱是一個完全合格的域名。因此,對於每個外部網域名稱查詢,可能會有四到五個額外的呼叫,這可能會讓 CoreDNS Pod 不堪重負。

若要解決此問題,請將 ndots 變更為 1,就只要尋找單一個點。或者,在您查詢或使用的網域末尾附加一個點 (.):

nslookup example.com.

考慮 VPC 解析程式 (AmazonProvidedDNS) 限制

Amazon Virtual Private Cloud (Amazon VPC) 解析程式每個網路介面只能接受每秒 1024 個封包的最大硬性限制。如果同一個節點上有多個 CoreDNS Pod,則外部網域查詢會有比較高的機率達到此限制。

若要使用 PodAntiAffinity 規則來排程個別執行個體上的 CoreDNS Pod,請將下列選項新增至 CoreDNS 部署:

podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - podAffinityTerm:
      labelSelector:
        matchExpressions:
        - key: k8s-app
          operator: In
          values:
          - kube-dns
      topologyKey: kubernetes.io/hostname
    weight: 100

**注意:**如需有關 PodAntiAffinity的詳細資訊,請參閱 Kubernetes 網站上的 Pod 間相似性和反相似性

使用 tcpdump 從 Amazon EKS 工作節點擷取 CoreDNS 封包

為協助診斷 DNS 解析問題,請使用 tcpdump 工具執行封包擷取:

  1. 尋找其中執行 CoreDNS Pod 的工作節點:

    kubectl get pod -n kube-system -l k8s-app=kube-dns -o wide
  2. 使用 SSH 連線至正在執行 CoreDNS Pod 的工作節點,然後安裝 tcpdump 工具:

    sudo yum install tcpdump –y
  3. 尋找工作節點上的 CoreDNS Pod 程序 ID:

    ps ax | grep coredns
  4. 從工作節點,在 CoreDNS Pod 網路上執行封包擷取,以監控 UDP 連接埠 53 上的網路流量:

    sudo nsenter -n -t PID tcpdump udp port 53
  5. 從單獨的終端,取得 CoreDNS 服務和 Pod IP 地址:

    kubectl describe svc kube-dns -n kube-system

    注意:記下位於 IP 欄位中的服務 IP,以及位於端點欄位中的 Pod IP。

  6. 啟動 Pod 來測試 DNS 服務。下列範例使用 Ubuntu 容器映像檔:

    kubectl run ubuntu --image=ubuntu sleep 1d
    
    kubectl exec -it ubuntu sh
  7. 使用 nslookup 工具針對一個網域執行 DNS 查詢,如 amazon.com

    nslookup amazon.com

    針對 CoreDNS 服務 IP 地址明確執行相同的查詢:

    nslookup amazon.com COREDNS_SERVICE_IP

    針對每個 CoreDNS Pod IP 地址執行查詢:

    nslookup amazon.com COREDNS\_POD\_IP

    **注意:**如果您有多個 CoreDNS Pod 在執行,請執行多個查詢,以便至少將一個查詢傳送至您要從中擷取流量的 Pod。

  8. 檢閱封包擷取結果。

    如果您受監控的 CoreDNS Pod 遇到 DNS 查詢逾時,而且您在封包擷取中看不到查詢,請檢查您的網路連線。請務必檢查工作節點之間的網路連線能力。

    如果您看到針對未擷取的 Pod IP 地址的 DNS 查詢逾時,請在相關工作節點上執行另一個封包擷取。

    若要儲存封包擷取的結果,請在 tcpdump 命令中新增 -w FILE_NAME 旗標。下列範例會將結果寫入名為 capture.pcap 的檔案:

    tcpdump -w capture.pcap udp port 53

相關資訊

適用於 Kubernetes 叢集 DNS 的 CoreDNS GA

(Kubernetes 網站上)

AWS 官方
AWS 官方已更新 6 個月前