請先設定 exec 探查逾時,再升級至 GKE 1.35 版


本頁說明如何準備存活、就緒和啟動探測,以便在將 Google Kubernetes Engine (GKE) 叢集升級至 1.35 以上版本前,為這些探測中的指令設定逾時。

關於 exec 探測的逾時

從 GKE 1.35 版開始,Kubernetes 會強制執行執行中、就緒和啟動探測器 exec 欄位中指令的逾時。探測規格中的 timeoutSeconds 欄位會定義 Kubernetes 等待探測完成任何動作的時間長度。如果省略這個欄位,預設值為 1,表示任何動作都有一秒的時間完成。

在 1.35 之前的 GKE 版本中,Kubernetes 會忽略 exec 探查指令 timeoutSeconds 欄位中的值。舉例來說,假設存活探針具有下列屬性:

  • timeoutSeconds 欄位中的 5 值。
  • exec.command 欄位中的指令需要 10 秒才能完成。

在 1.35 之前的版本中,Kubernetes 會忽略這五秒的逾時時間,並錯誤地回報探查成功。在 1.35 以上版本中,Kubernetes 會在五秒後正確地讓探查失敗。

Kubernetes 忽略 exec 探查逾時的行為,可能會導致探查無限期執行,進而隱藏應用程式的問題,或導致無法預測的行為。在 GKE 1.35 以上版本中,Kubernetes 會正確強制執行指令逾時,因此探查行為會與開放原始碼 Kubernetes 一致,且可預測。

強制執行 exec 探查逾時的影響

這是 GKE 1.35 以上版本中的重大變更,有助於提升 GKE 工作負載的穩定性和可靠性。將叢集升級至 1.35 以上版本時,如果工作負載具有下列其中一項屬性的 exec 探查,您可能會發現工作負載出現異常行為:

  • 省略 timeoutSeconds 欄位:在 1.35 以上版本中,這些探測器有一秒的時間可成功完成指令。如果指令無法在一秒內順利完成,探測器就會正確回報失敗。
  • 指定較短的逾時時間:在 1.35 以上版本中,逾時時間短於指令完成時間的探查會正確回報失敗。

在 GKE 1.34 版和更早版本中,如果 exec 探針符合下列任一條件,Kubernetes 就會回報錯誤。不過,這些 exec 探針中的指令仍可執行完畢,因為探針錯誤並非探針失敗

如果您未指定更準確的逾時時間,且指令完成時間超過現有的逾時時間,探測器會在 1.35 以上版本中回報失敗。視探測類型而定,探測失敗時的行為如下:

  • 有效性探測:如果指令逾時導致有效性探測失敗,Kubernetes 會假設應用程式失敗,並重新啟動容器。如果探測器反覆失敗,Pod 可能會陷入當機迴圈,並顯示 CrashLoopBackOff Pod 狀態。
  • 就緒探測:如果指令逾時導致就緒探測失敗,Kubernetes 會更新 Ready Pod 狀況,並顯示 False 狀態。Kubernetes 會等到探測作業成功後,再將流量傳送至 Pod。如果支援服務的所有 Pod 都有 Ready 條件的 False 狀態,您可能會發現服務中斷。
  • 啟動探測:如果啟動探測失敗,Kubernetes 會假設應用程式啟動失敗,並重新啟動容器。如果探針反覆失敗,Pod 可能會陷入當機迴圈,並處於 CrashLoopBackOff Pod 狀態。

已暫停自動升級

如果 GKE 偵測到叢集中的工作負載可能會受到這項變更影響,就會暫停自動升級至 1.35 版。如果版本 1.35 是控制層和節點的自動升級目標,符合下列任一條件,GKE 就會繼續自動升級:

  • 您已使用逾時值更新工作負載探查,且 GKE 在七天內未偵測到潛在問題。
  • 1.34 版在發布管道中終止支援

找出受影響的叢集或工作負載

以下各節說明如何找出可能受這項異動影響的叢集或工作負載。

使用指令列檢查 Kubernetes 事件

在 GKE 1.34 版和更早版本中,您可以手動檢查叢集中的 Kubernetes 事件,找出完成時間超過現有逾時期間的 exec 探查。Kubernetes 會為這些探查新增含有 command timed out 訊息的事件。這個方法有助於找出因逾時值過短而發生問題的工作負載。

如要找出受影響的工作負載,請執行下列其中一項操作:

使用指令碼在多個叢集中尋找工作負載

下列 Bash 指令碼會疊代kubeconfig 檔案中的所有叢集,找出受影響的工作負載。這項指令碼會檢查所有現有且可存取的 Kubernetes 環境中,是否有 exec 探查逾時錯誤,並將結果寫入名為 affected_workloads_report.txt 的文字檔。如要執行這項指令碼,請按照下列步驟操作:

  1. 將下列指令碼儲存為 execprobe-timeouts.sh

    #!/bin/bash
    
    # This script checks for exec probe timeouts across all existing and reachable
    # Kubernetes contexts and writes the findings to a text file, with one
    # row for each affected workload, including its cluster name.
    
    # --- Configuration ---
    OUTPUT_FILE="affected_workloads_report.txt"
    # -------------------
    
    # Check if kubectl and jq are installed
    if ! command -v kubectl &> /dev/null || ! command -v jq &> /dev/null; then
        echo "Error: kubectl and jq are required to run this script." >&2
        exit 1
    fi
    
    echo "Fetching all contexts from your kubeconfig..."
    
    # Initialize the report file with a formatted header
    printf "%-40s | %s\n" "Cluster Context" "Impacted Workload" > "$OUTPUT_FILE"
    
    # Get all context names from the kubeconfig file
    CONTEXTS=$(kubectl config get-contexts -o name)
    
    if [[ -z "$CONTEXTS" ]]; then
      echo "No Kubernetes contexts found in your kubeconfig file."
      exit 0
    fi
    
    echo "Verifying each context and checking for probe timeouts..."
    echo "=================================================="
    
    # Loop through each context
    for CONTEXT in $CONTEXTS; do
      echo "--- Checking context: $CONTEXT ---"
    
      # Check if the cluster is reachable by running a lightweight command
      if kubectl --context="$CONTEXT" get ns --request-timeout=1s > /dev/null 2>&1; then
        echo "Context '$CONTEXT' is reachable. Checking for timeouts..."
    
        # Find timeout events based on the logic from the documentation
        AFFECTED_WORKLOADS_LIST=$(kubectl --context="$CONTEXT" get events --all-namespaces -o json | jq -r '.items[] | select((.involvedObject.namespace | type == "string") and (.involvedObject.namespace | endswith("-system") | not) and (.message | test("^(Liveness|Readiness|Startup) probe errored(.*): command timed out(.*)|^ * probe errored and resulted in .* state: command timed out.*"))) | .involvedObject.kind + "/" + .involvedObject.name' | uniq)
    
        if [[ -n "$AFFECTED_WORKLOADS_LIST" ]]; then
          echo "Found potentially affected workloads in context '$CONTEXT'."
    
          # Loop through each affected workload and write a new row to the report
          # pairing the context with the workload.
          while IFS= read -r WORKLOAD; do
            printf "%-40s | %s\n" "$CONTEXT" "$WORKLOAD" >> "$OUTPUT_FILE"
          done <<< "$AFFECTED_WORKLOADS_LIST"
        else
          echo "No workloads with exec probe timeouts found in context '$CONTEXT'."
        fi
      else
        echo "Context '$CONTEXT' is not reachable or the cluster does not exist. Skipping."
      fi
      echo "--------------------------------------------------"
    done
    
    echo "=================================================="
    echo "Script finished."
    echo "A detailed report of affected workloads has been saved to: $OUTPUT_FILE"
    
  2. 執行指令碼:

    bash execprobe-timeouts.sh
    
  3. 讀取 affected_workloads_report.txt 檔案的內容:

    cat affected_workloads_report.txt
    

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

    Cluster Context                   | Impacted Workload
    -----------------------------------------|----------------------------
    gke_my-project_us-central1-c_cluster-1   | Pod/liveness1-exec
    gke_my-project_us-central1-c_cluster-1   | Deployment/another-buggy-app
    gke_my-project_us-east1-b_cluster-2      | Pod/startup-probe-test
    

使用指令列在特定叢集中尋找工作負載

如要找出特定叢集中受影響的工作負載,可以使用 kubectl 工具檢查 exec 探查逾時錯誤。請針對執行 1.34 版或更舊版本的每個 GKE 叢集,按照下列步驟操作:

  1. 連線至叢集:

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

    更改下列內容:

    • CLUSTER_NAME:叢集名稱。
    • LOCATION:叢集控制平面的位置,例如 us-central1
  2. 檢查是否有事件指出 exec 探查發生逾時錯誤:

    kubectl get events --all-namespaces -o json |
        jq -r '.items[] | select((.involvedObject.namespace | type == "string") and (.involvedObject.namespace | endswith("-system") | not) and (.message | test("^(Liveness|Readiness|Startup) probe errored(.*): command timed out(.*)|^ * probe errored and resulted in .* state: command timed out.*"))) | "\(.involvedObject.kind)/\(.involvedObject.name)        Namespace: \(.involvedObject.namespace)"'
    

    這項指令會忽略許多系統命名空間中的工作負載。如果存在受影響的工作負載,輸出結果會與下列內容相似:

    Pod/liveness1-exec      Namespace: default
    
  3. 針對執行 1.35 之前 GKE 版本的每個叢集,重複上述步驟。

在 Cloud Logging 中找出受影響的叢集和工作負載

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

    前往「Logs Explorer」頁面

  2. 如要開啟查詢編輯器,請點選「顯示查詢」切換鈕。

  3. 執行以下查詢:

    jsonPayload.message=~" probe errored and resulted in .* state: command timed out" OR jsonPayload.message=~" probe errored : command timed out"
    

    輸出內容是探查錯誤清單,這些錯誤是由完成時間超過所設逾時期間的指令所造成。

請先更新受影響的工作負載,再升級至 1.35 版

找出受影響的工作負載後,請更新受影響的探針。

  1. 檢查每個受影響 Pod 的有效性、完備性和啟動探測,並判斷適當的 timeoutSeconds 值。這個值應夠長,才能在正常情況下順利執行指令。詳情請參閱「設定執行中、就緒和啟動探測器」。
  2. 開啟受影響工作負載的資訊清單檔案,然後新增或修改存活、就緒或啟動探查的 timeoutSeconds 欄位。舉例來說,下列存活探針的 timeoutSeconds 欄位值為 10

    spec:
      containers:
      - name: my-container
        image: my-image
        livenessProbe:
          exec:
            command:
            - cat
            - /tmp/healthy
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 10
    
  3. 將更新後的資訊清單套用至叢集。

  4. 按照「使用指令列檢查 Kubernetes 事件」一文中的步驟,檢查更新後的探測器是否有錯誤。

更新並測試所有受影響的工作負載後,即可將叢集升級至 GKE 1.35 版。