排解 kubectl 指令列工具的問題

使用 Google Kubernetes Engine (GKE) 時,如果 kubectl 指令列工具發生問題,可能會導致您無法部署應用程式或管理叢集資源。這些問題通常分為兩類:驗證失敗 (叢集無法辨識您的身分),以及連線失敗 (工具無法連線至叢集的控制層)。

這個頁面可協助您診斷及解決這些問題。瞭解如何排解各種驗證問題,以及偵錯 kubectl 工具與叢集控制層之間的連線問題。瞭解如何檢查是否已安裝及設定必要外掛程式,並查看 SSH 和 Konnectivity 等服務的網路政策和防火牆注意事項。

如果您使用 kubectl 指令管理 GKE 上的應用程式或叢集資源,請務必瞭解這項資訊。對於依賴 kubectl 指令處理日常核心工作的應用程式開發人員、平台管理員和營運人員來說,這項功能尤其重要。如要進一步瞭解 內容中提及的常見角色和範例工作 Google Cloud ,請參閱「常見的 GKE 使用者角色和 工作」。

如需相關資訊,請參閱下列資源:

驗證和授權錯誤

如果使用 kubectl 指令列工具指令時發生驗證和授權相關錯誤,請參閱下列章節的建議。

錯誤:401 (未授權)

連線至 GKE 叢集時,您可能會收到驗證和授權錯誤,並附帶 HTTP 狀態碼 401 (Unauthorized)。如果您嘗試從本機環境在 GKE 叢集中執行 kubectl 指令,就可能會發生這個問題。詳情請參閱「問題:驗證和授權錯誤」。

錯誤:驗證範圍不足

執行 gcloud container clusters get-credentials 時,您可能會收到下列錯誤訊息:

ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Request had insufficient authentication scopes.

發生這個錯誤的原因是,您嘗試從沒有 cloud-platform 範圍的 Compute Engine VM 存取 GKE API。

如要解決這項錯誤,請授予缺少的 cloud-platform 範圍。如要瞭解如何變更 Compute Engine VM 執行個體的範圍,請參閱 Compute Engine 說明文件中的「為執行個體建立及啟用服務帳戶」一文。

錯誤:找不到可執行檔 gke-gcloud-auth-plugin

嘗試執行 kubectl 指令或與 GKE 互動的自訂用戶端時,可能會出現類似下列的錯誤訊息:

Unable to connect to the server: getting credentials: exec: executable gke-gcloud-auth-plugin not found

It looks like you are trying to use a client-go credential plugin that is not installed.

To learn more about this feature, consult the documentation available at:
      https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins

Visit cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin to install gke-gcloud-auth-plugin.
Unable to connect to the server: getting credentials: exec: fork/exec /usr/lib/google-cloud-sdk/bin/gke-gcloud-auth-plugin: no such file or directory

如要解決這個問題,請按照「安裝必要外掛程式」一文的說明安裝 gke-gcloud-auth-plugin。

錯誤:找不到驗證提供者

如果 kubectl 或自訂 Kubernetes 用戶端是以 Kubernetes client-go 1.26 以上版本建構,就會發生下列錯誤:

no Auth Provider found for name "gcp"

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

  1. 如「安裝必要外掛程式」一節所述,安裝 gke-gcloud-auth-plugin。

  2. 更新至最新版 gcloud CLI:

    gcloud components update
    
  3. 更新 kubeconfig 檔案:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是區域叢集,請提供區域;如果是可用區叢集,請提供可用區。

錯誤:gcp 驗證外掛程式已淘汰,請改用 gcloud

安裝 gke-gcloud-auth-plugin並對 GKE 叢集執行 kubectl 指令後,可能會看到下列警告訊息:

WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.

如果用戶端版本低於 1.26,就會顯示這則訊息。

如要解決這個問題,請要求客戶改用gke-gcloud-auth-plugin 驗證外掛程式:

  1. 在文字編輯器中開啟 Shell 登入指令碼:

    Bash

    vi ~/.bashrc

    Zsh

    vi ~/.zshrc

    如果使用 PowerShell,請略過這個步驟。

  2. 設定下列環境變數:

    Bash

    export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    

    Zsh

    export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    

    PowerShell

    [Environment]::SetEnvironmentVariable('USE_GKE_GCLOUD_AUTH_PLUGIN', True, 'Machine')
    
  3. 在環境中套用變數:

    Bash

    source ~/.bashrc

    Zsh

    source ~/.zshrc
    

    PowerShell

    結束終端機,並開啟新的終端機工作階段。

  4. 更新 gcloud CLI:

    gcloud components update
    
  5. 驗證叢集:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是區域叢集,請提供區域;如果是可用區叢集,請提供可用區。

問題:找不到 kubectl 指令

如果收到找不到 kubectl 指令的訊息,請重新安裝 kubectl 二進位檔,並設定 $PATH 環境變數:

  1. 安裝 kubectl 二進位檔:

    gcloud components update kubectl
    
  2. 安裝程式提示您修改 $PATH 環境變數時,請輸入 y 繼續。修改這個變數後,您可以使用 kubectl 指令,不必輸入完整路徑。

    或者,您也可以在殼層儲存環境變數的位置 (例如 ~/.bashrc 或 macOS 中的 ~/.bash_profile) 新增下列程式碼:

    export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/
    
  3. 執行下列指令,載入更新後的檔案。以下範例使用 .bashrc:

    source ~/.bashrc
    

    如果使用 macOS,請改用 ~/.bash_profile,而非 .bashrc。

問題:kubectl 指令傳回「connection refused」錯誤

如果 kubectl 指令傳回「connection refused」錯誤,請使用下列指令設定叢集環境:

gcloud container clusters get-credentials CLUSTER_NAME \
       --location=CONTROL_PLANE_LOCATION

更改下列內容:

  • CLUSTER_NAME:叢集名稱。
  • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是區域叢集,請提供區域;如果是可用區叢集,請提供可用區。

如果不確定要輸入什麼叢集名稱或位置,請使用下列指令列出叢集:

gcloud container clusters list

錯誤:kubectl 指令逾時

如果您建立叢集,並嘗試對叢集執行 kubectl 指令,但 kubectl 指令逾時,您會看到類似下列內容的錯誤訊息:

  • Unable to connect to the server: dial tcp IP_ADDRESS: connect: connection timed out
  • Unable to connect to the server: dial tcp IP_ADDRESS: i/o timeout。

這些錯誤表示 kubectl 無法與叢集控制層通訊。

如要解決這個問題,請驗證並設定叢集所在環境,並確保叢集連線正常:

  1. 前往 $HOME/.kube/config 或執行 kubectl config view 指令,確認設定檔包含叢集內容和控制層的外部 IP 位址。

  2. 設定叢集憑證:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION \
        --project=PROJECT_ID
    

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • CONTROL_PLANE_LOCATION:叢集控制層的 Compute Engine 位置。如果是區域叢集,請提供區域;如果是可用區叢集,請提供可用區。
    • PROJECT_ID:叢集建立所在專案的 ID。
  3. 如果您已在叢集中啟用授權網路,請確認現有授權網路清單包含您嘗試連線的電腦傳出 IP。您可以在控制台中找到現有的授權網路,也可以執行下列指令:

    gcloud container clusters describe CLUSTER_NAME \
        --location=CONTROL_PLANE_LOCATION \
        --project=PROJECT_ID \
        --format "flattened(controlPlaneEndpointsConfig.ipEndpointsConfig.authorizedNetwork
    sConfig.cidrBlocks[])"
    

    如果電腦的輸出 IP 不在先前指令輸出內容的授權網路清單中,請完成下列其中一個步驟:

錯誤:kubectl 指令傳回「failed to negotiate an api version」(無法協商 API 版本)

如果 kubectl 指令傳回 failed to negotiate an API version 錯誤,請確認 kubectl 具有驗證憑證:

gcloud auth application-default login

問題:kubectl、logs、attach、exec 或 port-forward 指令停止回應

如果 kubectl logs、attach、exec 或 port-forward 指令停止回應,通常表示 API 伺服器無法與節點通訊。

首先,請檢查叢集是否有任何節點。如果叢集中的節點數量已縮減為零,指令將無法運作。如要解決這個問題,請調整叢集大小,使其至少有一個節點。

如果叢集至少有一個節點,請檢查您是否使用 SSH 或 Konnectivity Proxy 通道來啟用安全通訊。以下各節將討論各項服務的專屬疑難排解步驟:

疑難排解 SSH 問題

如果您使用 SSH,GKE 會將安全殼層公開金鑰檔案儲存在 Compute Engine 專案中繼資料中。所有使用 Google 提供映像檔的 Compute Engine VM,都會定期檢查專案的通用中繼資料和執行個體的中繼資料,找出要新增至 VM 授權使用者清單的 SSH 金鑰。GKE 也會在 Compute Engine 網路中新增防火牆規則,允許從控制層的 IP 位址透過 SSH 存取叢集中的每個節點。

下列設定可能會導致 SSH 通訊問題:

  • 網路的防火牆規則不允許從控制層進行 SSH 存取。

    所有 Compute Engine 網路都會建立名為 default-allow-ssh 的防火牆規則,允許來自所有 IP 位址的 SSH 存取權 (需要有效的私密金鑰)。GKE 也會為每個公開叢集插入 gke-CLUSTER_NAME-RANDOM_CHARACTERS-ssh 格式的 SSH 規則,允許從叢集的控制層到叢集節點的 SSH 存取。

    如果這兩項規則都不存在,控制層就無法開啟 SSH 通道。

    如要確認這是否為問題原因,請檢查設定是否包含這些規則。

    如要解決這個問題,請找出叢集所有節點上的標記,然後重新新增防火牆規則,允許從控制層的 IP 位址存取具有該標記的 VM。

  • 專案的 ssh-keys 一般中繼資料項目已達上限。

    如果專案中名為 ssh-keys 的中繼資料項目即將達到大小上限,GKE 就無法新增自己的安全殼層金鑰來開啟 SSH 通道。

    如要確認這是否為問題,請檢查 ssh-keys 清單的長度。您可以執行下列指令,查看專案的中繼資料,並視需要加入 --project 旗標:

    gcloud compute project-info describe [--project=PROJECT_ID]
    

    如要解決這個問題,請刪除一些不再需要的 安全殼層金鑰。

  • 您已在叢集中的 VM 上,設定鍵為 ssh-keys 的中繼資料欄位。

    VM 上的節點代理程式會優先使用執行個體專屬的安全殼層金鑰,而非專案範圍的安全殼層金鑰,因此如果您已在叢集節點上設定任何安全殼層金鑰,節點就不會採用專案中繼資料中的控制層安全殼層金鑰。

    如要確認是否為這個問題,請執行 gcloud compute instances describe VM_NAME,並在 metadata 中尋找 ssh-keys 欄位。

    如要解決這個問題,請從執行個體中繼資料刪除個別執行個體的安全殼層金鑰。

排解 Konnectivity Proxy 問題

您可以檢查下列系統 Deployment,判斷叢集是否使用 Konnectivity Proxy:

kubectl get deployments konnectivity-agent --namespace kube-system

如果叢集使用 Konnectivity Proxy,輸出內容會與下列內容類似:

NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
konnectivity-agent   3/3     3            3           18d

確認您使用的是 Konnectivity Proxy 後,請確保 Konnectivity 代理程式具備必要的防火牆存取權,且網路政策設定正確無誤。

允許必要的防火牆存取權

確認網路的防火牆規則允許存取下列通訊埠:

  • 控制層通訊埠:建立叢集時,Konnectivity 代理程式會透過通訊埠 8132 建立與控制層的連線。執行 kubectl 指令時,API 伺服器會使用這個連線與叢集通訊。請務必允許輸出流量透過通訊埠 8132 (API 伺服器使用 443) 傳送至叢集控制層。如果您有拒絕輸出存取權的規則,可能需要修改規則或建立例外狀況。
  • kubelet 通訊埠:由於 Konnectivity 代理程式是部署在叢集節點上的系統 Pod,請確保防火牆規則允許下列類型的流量:

    • 從 Pod 範圍傳送至工作負載 10250 埠的連入流量。
    • 從 Pod 範圍輸出的流量。

    如果防火牆規則不允許這類流量,請修改規則。

調整網路政策

如果叢集的網路政策執行下列任一操作,Konnectivity Proxy 可能會發生問題:

  • 封鎖從 kube-system 命名空間到 workload 命名空間的 Ingress
  • 封鎖通訊埠 8132 上的輸出流量至叢集控制層

如果輸入流量遭到工作負載 Pod 的網路政策封鎖,konnectivity-agent 記錄會包含類似下列內容的錯誤訊息:

"error dialing backend" error="dial tcp POD_IP_ADDRESS:PORT: i/o timeout"

在錯誤訊息中,POD_IP_ADDRESS 是工作負載 Pod 的 IP 位址。

如果網路政策封鎖輸出,konnectivity-agent 記錄會包含類似下列的錯誤訊息:

"cannot connect once" err="rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp CP_IP_ADDRESS:8132: i/o timeout

在錯誤中,CP_IP_ADDRESS 是叢集控制層的 IP 位址。

叢集正常運作不需要這些功能。 如果您想讓叢集網路完全不開放外部存取,請注意,這類功能將無法運作。

如要確認網路政策輸入或輸出規則是否導致問題,請執行下列指令,在受影響的命名空間中找出網路政策:

kubectl get networkpolicy --namespace AFFECTED_NAMESPACE

如要解決輸入政策的問題,請在網路政策的 spec.ingress 欄位中新增下列內容:

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        kubernetes.io/metadata.name: kube-system
    podSelector:
      matchLabels:
        k8s-app: konnectivity-agent

如要解決輸出政策問題,請在網路政策的 spec.egress 欄位中新增下列項目:

egress:
- to:
  - ipBlock:
      cidr: CP_IP_ADDRESS/32
  ports:
  - protocol: TCP
    port: 8132

如果網路政策同時使用輸入和輸出規則,請考慮調整這兩項規則。

調整 IP 偽裝代理

如果來源 IP 位址位於 Pod IP 位址範圍內,叢集控制層會接受來自 Konnectivity 代理程式的流量。如果您修改 ip-masq-agent 的設定,將傳送至叢集控制平面的流量來源 IP 位址偽裝起來,Konnectivity 代理程式可能會發生連線錯誤。

如要解決這個問題,並確保從 Konnectivity 代理程式到叢集控制層的流量不會偽裝成節點 IP 位址,請將控制層 IP 位址新增至 ip-masq-agent ConfigMap 中的 nonMasqueradeCIDRs 清單:

nonMasqueradeCIDRs:
- CONTROL_PLANE_IP_ADDRESS/32

如要進一步瞭解這項設定,請參閱「IP 偽裝代理程式」。

錯誤:kubectl 指令失敗,並顯示沒有可用的代理程式錯誤

執行需要從 GKE 控制層連線至 Pod 的 kubectl 指令時 (例如 kubectl exec、kubectl logs 或 kubectl port-forward),指令可能會失敗,並顯示類似下列內容的錯誤訊息:

Error from server: error dialing backend: No agent available
failed to call webhook: Post "https://WEBHOOK_SERVICE.WEBHOOK_NAMESPACE.svc:PORT/PATH?timeout=10s": No agent available
v1beta1.metrics.k8s.io failed with: failing or missing response from https://NODE_IP:10250/apis/metrics.k8s.io/v1beta1: Get "https://NODE_IP:10250/apis/metrics.k8s.io/v1beta1": No agent available

這些錯誤表示 Konnectivity 發生問題,Konnectivity 是 GKE 控制層與叢集節點之間的安全通訊通道。具體來說,這表示控制層上的 konnectivity-server 無法連線至 kube-system 命名空間中任何健康狀態良好的 konnectivity-agent Pod。

如要解決這個問題,請嘗試下列解決方法:

  1. 確認 konnectivity-agent Pod 的健康狀態:

    1. 檢查 konnectivity-agent Pod 是否正在執行:

      kubectl get pods -n kube-system -l k8s-app=konnectivity-agent
      

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

      NAME                                   READY   STATUS    RESTARTS  AGE
      konnectivity-agent-abc123def4-xsy1a    2/2     Running   0         31d
      konnectivity-agent-abc123def4-yza2b    2/2     Running   0         31d
      konnectivity-agent-abc123def4-zxb3c    2/2     Running   0         31d
      

      查看「Status」欄中的值。如果 Pod 的狀態為 Running,請檢查記錄,找出連線問題。否則,請調查 Pod 未執行的原因。

    2. 查看記錄檔,瞭解連線問題。如果 Pod 的狀態為 Running,請檢查記錄是否有連線問題。由於 kubectl logs 指令取決於 Konnectivity,請在Google Cloud 控制台中使用記錄檔探索工具:

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

        前往 Logs Explorer

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

        resource.type="k8s_container"
        resource.labels.cluster_name="CLUSTER_NAME"
        resource.labels.namespace_name="kube-system"
        labels."k8s-pod/k8s-app"="konnectivity-agent"
        resource.labels.container_name="konnectivity-agent"
        

        將 CLUSTER_NAME 替換為叢集名稱。

      3. 點選「執行查詢」。

      4. 查看輸出內容。查看 konnectivity-agent 記錄時,請找出指出代理程式無法連線原因的錯誤。驗證或權限錯誤通常表示設定錯誤的 Webhook 封鎖權杖評論。「連線遭拒」或「逾時」錯誤通常表示防火牆規則或網路政策封鎖了 TCP 通訊埠 8132 上傳送至控制層的流量,或是封鎖了 Konnectivity 代理程式和其他節點之間的流量。憑證錯誤表示防火牆或 Proxy 正在檢查並干擾加密的 TLS 流量。

    3. 調查 Pod 無法執行的原因。如果 Pod 的狀態為 Pending 或其他非執行中狀態,請調查原因。konnectivity-agent 會以 Deployment 的形式執行,而非 DaemonSet。由於代理程式 Pod 是以 Deployment 形式執行,因此只需要在部分節點上執行。不過,如果該特定節點子集無法使用,整個服務可能會失敗。

      Pod 未執行的常見原因包括:

      • 防止 Pod 排程的自訂節點 taint。
      • 節點資源 (CPU 或記憶體) 不足。
      • 封鎖 GKE 系統映像檔的限制性二進位授權政策。

      如要進一步瞭解特定 Pod 未執行的原因,請使用 kubectl describe 指令:

      kubectl describe pod POD_NAME -n kube-system
      

      將 POD_NAME 替換為未執行的 Pod 名稱。

  2. 調查准入 Webhook,確保沒有任何 Webhook 封鎖 TokenReview API 要求。konnectivity-agent 依賴服務帳戶權杖,因此干擾權杖審查可能會導致代理程式無法連線。如果問題出在 Webhook,Konnectivity 無法復原,直到移除或修復有問題的 Webhook 為止。

  3. 確認防火牆規則允許從 GKE 節點輸出 TCP 流量,傳向控制層 IP 位址的通訊埠 8132。konnectivity-agent 必須透過這個連線才能連上 Konnectivity 服務。詳情請參閱「允許必要的防火牆存取權」。

  4. 請確認沒有任何網路政策規則會限制必要的 Konnectivity 流量。網路政策規則應允許 kube-system 命名空間內的叢集內流量 (Pod 對 Pod),以及從 konnectivity-agent Pod 到 GKE 控制層的輸出流量。

排解 kubectl 用戶端節流問題

問題:

使用 kubectl 時,您可能會遇到用戶端節流,錯誤訊息包含下列內容:...Throttling request took 1.002582473s, request: GET:... 或 Waited for 1.183040416s due to client-side throttling, not priority and fairness, request: GET: ...。

原因:

執行 kubectl 指令時,系統會先從 API 伺服器快取資源清單。這份清單對應於 API 伺服器提供的自訂資源定義 (CRD)。

如果 GKE 叢集有大量 CRD (例如 300 個以上),kubectl 會向 API 伺服器傳送大量要求,以建構或重新整理快取。為避免 API 伺服器超載,kubectl 會自行調節。

解決方法:

這類節流錯誤訊息是預期行為,是由 kubectl 端的用戶端節流所導致。這個問題應該會自行解決。

後續步驟