在升级到 GKE 1.35 版之前配置 exec 探测超时

本页面介绍了如何在将 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 会忽略此 5 秒超时,并错误地将探测报告为成功。在 1.35 版及更高版本中,Kubernetes 会在 5 秒后正确地使探测失败。

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 会假定应用有故障并重启容器。在低于 1.35 的版本中,超时可能只会生成警告事件,但不会强制重启容器。如果探测反复失败,您的 Pod 可能会陷入崩溃循环,并显示 CrashLoopBackOff Pod 状态。
  • 就绪性探测:如果就绪性探测因命令超时而失败,Kubernetes 会更新 Ready Pod 条件并将其状态设为 False。这意味着,在探测成功之前,Kubernetes 不会向 Pod 发送任何流量。在 GKE 1.35 及更高版本中,Pod 会从 Service 端点中移除。在低于 1.35 的版本中,超时可能只会生成警告事件,但不会从服务中移除 Pod。如果支持某项服务的所有 Pod 的 Ready 条件都处于 False 状态,该服务可能会出现中断。
  • 启动探测:如果启动探测失败,Kubernetes 会假定应用启动失败并重启容器。如果探测反复失败,您的 Pod 可能会陷入崩溃循环,并显示 CrashLoopBackOff Pod 状态。

已暂停自动升级

GKE 在检测到集群中的工作负载可能会受到此更改的影响时,会暂停自动升级到 1.35 版。如果 1.35 版是控制平面和节点的自动升级目标版本,并且满足以下任一条件,GKE 会恢复自动升级:

  • 您已使用超时值更新工作负载探测,并且 GKE 在 7 天内未检测到潜在问题。
  • 1.34 版在您的发布渠道中已达到支持终止日期

确定受影响的集群或工作负载

以下部分将介绍如何确定可能受此更改影响的集群或工作负载。

使用 GKE 建议和数据分析

GKE 会监控您的集群,并使用 Recommender 服务来识别受强制执行 exec 探测超时影响的集群。如果 GKE 检测到集群中的工作负载具有可能会超时的 exec 探测,则会在Cloud de Confiance 控制台中显示一条标题为配置工作负载的 exec 探测超时的建议。

获取分析洞见和建议

按照相关说明查看分析洞见和建议。 您可以使用 Cloud de Confiance 控制台获取分析洞见。您还可以使用 Google Cloud CLI 或 Recommender API,并使用以下子类型进行过滤:

  • EXEC_PROBE_TIMEOUT:exec 探测超时

对于有有效建议的集群,GKE 会暂停自动升级到 1.35 版,直到更新 exec 探测超时配置以支持无中断操作。

使用命令行检查 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. 针对运行 GKE 1.35 之前版本的每个集群重复执行上述步骤。

在 Cloud Logging 中查找受影响的集群和工作负载

  1. 在 Cloud de Confiance 控制台中,前往 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 版。