排查 Autopilot 集群问题


本页面介绍如何解决 Google Kubernetes Engine (GKE) Autopilot 集群的问题。

集群问题

无法创建集群:已注册 0 个节点

您在尝试通过已停用或没有所需权限的 IAM 服务账号创建 Autopilot 集群时会发生以下问题。集群创建失败,并显示以下错误消息:

All cluster resources were brought up, but: only 0 nodes out of 2 have registered.

如需解决此问题,请执行以下操作:

  1. 检查默认 Compute Engine 服务账号或您要使用的自定义 IAM 服务账号是否已停用:

    gcloud iam service-accounts describe SERVICE_ACCOUNT
    

    SERVICE_ACCOUNT 替换为服务账号电子邮件地址,例如 my-iam-account@my-first-project.iam.gserviceaccount.com

    如果服务账号已停用,则输出类似于以下内容:

    disabled: true
    displayName: my-service-account
    email: my-service-account@my-project.iam.gserviceaccount.com
    ...
    
  2. 如果服务账号已停用,请启用它:

    gcloud iam service-accounts enable SERVICE_ACCOUNT
    

如果在启用该服务账号后仍然出现该错误,请向该服务账号授予 GKE 所需的最低权限:

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:SERVICE_ACCOUNT" \
    --role roles/container.defaultNodeServiceAccount

当集群有 0 个节点时,命名空间卡在终止状态

当您在集群缩减至零个节点后删除集群中的命名空间时,会出现以下问题。metrics-server 组件无法接受命名空间删除请求,因为该组件没有副本。

如需诊断此问题,请运行以下命令:

kubectl describe ns/NAMESPACE_NAME

NAMESPACE_NAME 替换为命名空间的名称。

输出如下所示:

Discovery failed for some groups, 1 failing: unable to retrieve the complete
list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to
handle the request

如需解决此问题,请扩容任何工作负载以触发 GKE 来创建新节点。节点准备就绪后,命名空间删除请求会自动完成。在 GKE 删除命名空间后,请缩减工作负载。

扩缩问题

节点纵向扩容失败:Pod 存在不被安排的风险

当您在Google Cloud 项目中停用串行端口日志记录功能时,会出现以下问题。GKE Autopilot 集群需要串行端口日志记录功能才能有效调试节点问题。如果停用串行端口日志记录功能,则 Autopilot 无法预配节点来运行工作负载。

Kubernetes 事件日志中的错误消息类似于以下内容:

LAST SEEN   TYPE      REASON          OBJECT                          MESSAGE
12s         Warning   FailedScaleUp   pod/pod-test-5b97f7c978-h9lvl   Node scale up in zones associated with this pod failed: Internal error. Pod is at risk of not being scheduled

通过实施 compute.disableSerialPortLogging 限制条件的组织政策,可以在组织级层停用串行端口日志记录功能。您也可以在项目或虚拟机 (VM) 实例级层停用串行端口日志记录功能。

如需解决此问题,请执行以下操作:

  1. 要求您的 Google Cloud 组织政策管理员在您的 Autopilot 集群中移除项目中的 compute.disableSerialPortLogging 限制条件
  2. 如果您没有强制执行此限制条件的组织政策,请尝试在项目元数据中启用串行端口日志记录。此操作需要 compute.projects.setCommonInstanceMetadata IAM 权限

节点纵向扩容失败:GCE 资源不足

如果您的工作负载请求的资源超过该 Compute Engine 区域或可用区中可供使用的资源,则会出现以下问题。您的 Pod 可能会保持 Pending 状态。

  • 检查您的 Pod 事件:

    kubectl events --for='pod/POD_NAME' --types=Warning
    

    RESOURCE_NAME 替换为待处理 Kubernetes 资源的名称。例如 pod/example-pod

    输出类似于以下内容:

    LAST SEEN         TYPE            REASON                  OBJECT                   Message
    19m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    14m               Warning         FailedScheduling        pod/example-pod          gke.io/optimize-utilization-scheduler  0/2 nodes are available: 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
    12m (x2 over 18m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-f associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    34s (x3 over 17m) Warning         FailedScaleUp           cluster-autoscaler       Node scale up in zones us-central1-b associated with this pod failed: GCE out of resources. Pod is at risk of not being scheduled.
    

如需解决此问题,请尝试执行以下操作:

  • 在其他区域或可用区中部署 Pod。如果您的 Pod 具有可用区级限制(例如拓扑选择器),请尽可能移除该限制。如需了解相关说明,请参阅将 GKE Pod 放置在特定的可用区中
  • 在其他区域中创建集群并重试部署。
  • 尝试使用其他计算类。由较小的 Compute Engine 机器类型提供支持的计算类更有可能具有可用资源。例如,Autopilot 的默认机器类型具有最高可用性。如需查看计算类和相应机器类型的列表,请参阅何时使用特定计算类
  • 如果您运行 GPU 工作负载,则请求的 GPU 可能在您的节点位置不可用。请尝试在其他位置部署工作负载或请求其他类型的 GPU。

如需避免将来发生由资源可用性导致的纵向扩容问题,请考虑以下方法:

节点无法纵向扩容:已超出 Pod 可用区级资源

当 Autopilot 未在特定可用区为 Pod 预配新节点时,会发生以下问题,因为新节点会违反资源限制。

日志中的错误消息类似于以下内容:

    "napFailureReasons": [
            {
              "messageId": "no.scale.up.nap.pod.zonal.resources.exceeded",
              ...

此错误指的是 noScaleUp 事件,其中节点自动预配功能未为可用区中的 Pod 预配任何节点组

如果遇到此错误,请确认以下内容:

工作负载问题

工作负载因临时存储错误而卡住

如果您的 Pod 临时存储请求超过 GKE 1.28.6-gke.1317000 版及更高版本中的 Autopilot 最大值 10GiB,GKE 将不会创建 Pod。

如需诊断此问题,请描述工作负载控制器,例如 Deployment 或 Job:

kubectl describe CONTROLLER_TYPE/CONTROLLER_NAME

替换以下内容:

  • CONTROLLER_TYPE:工作负载控制器的类型,如 replicasetdaemonset。如需查看控制器类型列表,请参阅工作负载管理
  • CONTROLLER_NAME:卡住的工作负载的名称。

如果由于临时存储请求超出最大值而未创建 Pod,则输出类似于以下内容:

# lines omitted for clarity

Events:

{"[denied by autogke-pod-limit-constraints]":["Max ephemeral-storage requested by init containers for workload '' is higher than the Autopilot maximum of '10Gi'.","Total ephemeral-storage requested by containers for workload '' is higher than the Autopilot maximum of '10Gi'."]}

如需解决此问题,请更新您的临时存储请求,以使工作负载容器和 webhook 注入的容器所请求的临时存储总量小于或等于允许的最大值。如需详细了解最大值,请参阅 Autopilot 中的资源请求以了解正确的工作负载配置。

Pod 卡滞在“待处理”状态

如果您为 Pod 选择了特定节点,但 Pod 和 DaemonSet 中必须在该节点上运行的资源请求总和超过该节点的可分配容量上限,则 Pod 可能会卡在 Pending 状态。这可能会导致您的 Pod 变为 Pending 状态并保持未安排状态。

为避免此问题,请评估已部署的工作负载的大小,以确保它们不超过受支持的 Autopilot 资源请求上限

您还可以尝试在安排常规工作负载 Pod 之前安排 DaemonSet。

特定节点上的工作负载性能持续不可靠

在 GKE 1.24 及更高版本中,如果特定节点上的工作负载持续出现中断、崩溃或类似不可靠的行为,您可以使用以下命令封锁有问题的节点,从而将此节点告知 GKE:

kubectl drain NODE_NAME --ignore-daemonsets

NODE_NAME 替换为有问题的节点的名称。您可以通过运行 kubectl get nodes 找到节点名称。

GKE 会执行以下操作:

  • 从节点逐出现有工作负载并停止在该节点上调度工作负载。
  • 在其他节点上自动重新创建由控制器(例如 Deployment 或 StatefulSet)管理的任何被逐出的工作负载。
  • 终止保留在节点上的所有工作负载,并随着时间的推移修复或重新创建节点。
  • 如果您使用 Autopilot,GKE 会立即关闭并替换节点,并忽略任何已配置的 PodDisruptionBudget。

Pod 在空集群上进行调度所花的时间超过预期时间

当您将工作负载部署到没有其他工作负载的 Autopilot 集群时,会发生此事件。Autopilot 集群会从零个可用节点开始,如果集群为空,则缩减至零个节点以避免集群中有未使用的计算资源。在具有零个节点的集群中部署工作负载会触发纵向扩容事件。

如果您遇到这种情况,则 Autopilot 会按预期运行,无需执行任何操作。新节点启动后,您的工作负载将按预期部署。

检查您的 Pod 是否正在等待新节点:

  1. 描述待处理 Pod:

    kubectl describe pod POD_NAME
    

    POD_NAME 替换为待处理 Pod 的名称。

  2. 检查输出的 Events 部分。如果 Pod 正在等待新节点,则输出类似于以下内容:

    Events:
      Type     Reason            Age   From                                   Message
      ----     ------            ----  ----                                   -------
      Warning  FailedScheduling  11s   gke.io/optimize-utilization-scheduler  no nodes available to schedule pods
      Normal   TriggeredScaleUp  4s    cluster-autoscaler                     pod triggered scale-up: [{https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-9293c6db-grp 0->1 (max: 1000)} {https://www.googleapis.com/compute/v1/projects/example-project/zones/example-zone/instanceGroups/gk3-example-cluster-pool-2-d99371e7-grp 0->1 (max: 1000)}]
    

    TriggeredScaleUp 事件显示您的集群正在从零个节点纵向扩容到运行已部署的工作负载所需的节点数量。

系统 Pod 无法在空集群上进行调度

当您自己的工作负载都未在集群中运行时,就会发生此事件,从而导致集群缩减至零个节点。Autopilot 集群会从零个可用节点开始,如果您未在集群中运行任何工作负载,则缩减至零个节点。此行为可最大限度地减少集群中浪费的计算资源。

当集群缩减至零个节点时,GKE 系统工作负载将不会调度,并保持 Pending 状态。这是预期行为,无需采取任何措施。下次将工作负载部署到集群时,GKE 会扩容集群,且待处理的系统 Pod 将在这些节点上运行。

如需检查系统 Pod 是否因集群为空而处于待处理状态,请执行以下操作:

  1. 检查集群是否具有任何节点。

    kubectl get nodes
    

    输出如下所示,表明集群没有节点:

    No resources found
    
  2. 检查系统 Pod 的状态:

    kubectl get pods --namespace=kube-system
    

    输出类似于以下内容:

    NAME                                                       READY   STATUS    RESTARTS   AGE
    antrea-controller-horizontal-autoscaler-6d97f7cf7c-ngfd2   0/1     Pending   0          9d
    egress-nat-controller-84bc985778-6jcwl                     0/1     Pending   0          9d
    event-exporter-gke-5c5b457d58-7njv7                        0/2     Pending   0          3d5h
    event-exporter-gke-6cd5c599c6-bn665                        0/2     Pending   0          9d
    konnectivity-agent-694b68fb7f-gws8j                        0/2     Pending   0          3d5h
    konnectivity-agent-7d659bf64d-lp4kt                        0/2     Pending   0          9d
    konnectivity-agent-7d659bf64d-rkrw2                        0/2     Pending   0          9d
    konnectivity-agent-autoscaler-5b6ff64fcd-wn7fw             0/1     Pending   0          9d
    konnectivity-agent-autoscaler-cc5bd5684-tgtwp              0/1     Pending   0          3d5h
    kube-dns-65ccc769cc-5q5q7                                  0/5     Pending   0          3d5h
    kube-dns-7f7cdb9b75-qkq4l                                  0/5     Pending   0          9d
    kube-dns-7f7cdb9b75-skrx4                                  0/5     Pending   0          9d
    kube-dns-autoscaler-6ffdbff798-vhvkg                       0/1     Pending   0          9d
    kube-dns-autoscaler-8b7698c76-mgcx8                        0/1     Pending   0          3d5h
    l7-default-backend-87b58b54c-x5q7f                         0/1     Pending   0          9d
    metrics-server-v1.31.0-769c5b4896-t5jjr                    0/1     Pending   0          9d
    
  3. 检查系统 Pod 处于 Pending 状态的原因:

    kubectl describe pod --namespace=kube-system SYSTEM_POD_NAME
    

    SYSTEM_POD_NAME 替换为上一个命令的输出中任何系统 Pod 的名称。

    输出类似于以下内容:

    ...
    Events:
    Type     Reason            Age                       From               Message
    ----     ------            ----                      ----               -------
    Warning  FailedScheduling  4m35s (x27935 over 3d5h)  default-scheduler  no nodes available to schedule pods
    ...
    

    在输出中,FailedScheduling 事件的 Message 字段中的 no nodes available to schedule pods 值表示系统 Pod 未安排,因为集群为空。

禁止访问 GKE Autopilot 集群中的底层节点。因此,需要在 Pod 中运行 tcpdump 实用程序,然后使用 kubectl cp 命令进行复制。如果您通常从 GKE Autopilot 集群的 Pod 中运行 tcpdump 实用程序,则可能会看到以下错误:

    tcpdump: eth0: You don't have permission to perform this capture on that device
    (socket: Operation not permitted)

这是因为默认情况下,GKE Autopilot 会将丢弃 NET_RAW 功能的安全上下文应用于所有 Pod,以缓解潜在漏洞。例如:

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: tcpdump
  name: tcpdump
spec:
  containers:
  - image: nginx
    name: nginx
    resources:
      limits:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
      requests:
        cpu: 500m
        ephemeral-storage: 1Gi
        memory: 2Gi
    securityContext:
      capabilities:
        drop:
        - NET_RAW

作为解决方案,如果您的工作负载需要 NET_RAW 功能,则可以重新启用它:

  1. NET_RAW 功能添加到 Pod 的 YAML 规范的 securityContext 部分:

    securityContext:
      capabilities:
        add:
        - NET_RAW
    
  2. 从 Pod 中运行 tcpdump

    tcpdump port 53 -w packetcap.pcap
    tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    
  3. 使用 kubectl cp 命令将其复制到本地机器以供进一步分析:

    kubectl cp POD_NAME:/PATH_TO_FILE/FILE_NAME/PATH_TO_FILE/FILE_NAME
    
  4. 使用 kubectl exec 运行 tcpdump 命令以执行网络数据包捕获并重定向输出:

    kubectl exec -it POD_NAME -- bash -c "tcpdump port 53 -w -" > packet-new.pcap
    

后续步骤