问题排查


本页面介绍了针对使用 Google Kubernetes Engine (GKE) 时遇到的问题的排查步骤。

如果您需要其他帮助,请与 Cloud Customer Care 联系。

调试 Kubernetes 资源

对于 Kubernetes 资源,如果您遇到以下问题:

排查 kubectl 命令问题

本部分介绍了针对 kubectl 命令的几种问题类型的排查步骤。

问题:找不到 kubectl 命令

如果您收到一条消息,提示您未找到 kubectl 命令,请重新安装 kubectl 二进制文件并设置 $PATH 环境变量:

  1. 通过运行以下命令,安装 kubectl 二进制文件:

    gcloud components update kubectl
    
  2. 当安装程序弹出提示您修改 $PATH 环境变量时,请选择“是”。修改此变量后,您可以在使用 kubectl 命令时无需输入其完整路径。

    或者,将以下行添加到 shell 存储环境变量的任何位置,例如 ~/.bashrc(在 macOS 中是 ~/.bash_profile):

    export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/
    
  3. 运行以下命令以加载更新后的文件。以下示例使用 .bashrc

    source ~/.bashrc
    

    如果您使用的是 macOS,请使用 ~/.bash_profile 而不是 .bashrc

问题:kubectl 命令返回“连接被拒绝”错误

如果 kubectl 命令返回“连接被拒绝”错误,则需要使用以下命令设置集群上下文:

  gcloud container clusters get-credentials CLUSTER_NAME

如果您不确定要为 CLUSTER_NAME 输入什么内容,请使用以下命令列出您的集群:

  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=COMPUTE_LOCATION \
        --project=PROJECT_ID
    

    替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • COMPUTE_LOCATIONCompute Engine 位置
    • PROJECT_ID:在其中创建 GKE 集群的项目的 ID。
  3. 如果该集群是专用 GKE 集群,请确保其现有授权网络列表包含您尝试从中连接的机器的传出 IP。您可以在控制台中查找现有授权网络,也可以通过运行以下命令来查找:

    gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID \
        --format "flattened(masterAuthorizedNetworksConfig.cidrBlocks[])"
    

    如果上述命令输出的授权网络列表中未包含机器的传出 IP,请执行以下操作:

错误:kubectl 命令返回“无法协商 API 版本”错误

如果 kubectl 命令返回“无法协商 API 版本”错误,则需要确保 kubectl 具有身份验证凭据:

  gcloud auth application-default login

问题:kubectl logsattachexecport-forward 命令停止响应

如果 kubectl logsattachexecport-forward 命令停止响应,通常表示 API 服务器无法与节点通信。

首先,检查集群是否具有任何节点。如果您已将集群中的节点数缩减至零,则命令将无法运行。如需解决此问题,请调整集群大小,使其至少具有一个节点。

如果集群至少具有一个节点,请检查您是使用 SSH 还是 Konnectivity 代理隧道来实现安全通信。以下各部分介绍了特定于每种方法的问题排查步骤:

排查 SSH 问题

如果您使用的是 SSH,GKE 会在您的 Compute Engine 项目元数据中保存 SSH 公钥文件。使用 Google 提供的映像的所有 Compute Engine 虚拟机都会定期检查其项目的共同元数据及其实例的元数据,以使 SSH 公钥添加到虚拟机的授权用户列表中。GKE 还会为您的 Compute Engine 网络添加防火墙规则,以允许通过 SSH 实现从控制平面的 IP 地址到集群中每个节点的访问。

SSH 的问题可能是由以下原因造成的:

  • 您的网络的防火墙规则不允许通过 SSH 从控制平面访问。

    所有 Compute Engine 网络都使用名为 default-allow-ssh 的防火墙规则创建,该规则允许从所有 IP 地址进行 SSH 访问(需要使用有效的私钥)。GKE 还为每个公共集群插入一项 SSH 规则(格式为 gke-CLUSTER_NAME-RANDOM_CHARACTERS-ssh),该规则允许通过 SSH 实现专门从集群的控制平面到集群的节点的访问。

    若没有这些规则,则控制平面无法打开 SSH 隧道。

    如需验证是否是此原因导致的问题,请检查您的配置是否包含这些规则。

    如需解决此问题,请确定集群所有节点上的标记,然后重新添加防火墙规则,以允许从控制平面的 IP 地址访问具有该标记的虚拟机。

  • 您的项目的 ssh-keys 的公共元数据条目已满。

    如果项目名为“ssh-keys”的元数据条目接近大小上限,则 GKE 无法添加自己的 SSH 密钥来打开 SSH 隧道。

    如需验证是否存在此问题,请检查 ssh-keys 列表的长度。您可以通过运行以下命令并视情况添加 --project 标志来查看项目的元数据:

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

    如需解决此问题,请删除一些不再需要的 SSH 密钥

  • 您已在集群中的虚拟机上使用密钥“ssh-keys”设置元数据字段。

    相比项目范围的 SSH 密钥,虚拟机上的节点代理会优先使用每个实例的 ssh-keys,因此如果您在集群的节点上专门设置了任何 SSH 密钥,则节点不会采用项目元数据中控制平面的 SSH 密钥。

    如需验证是否存在此问题,请运行 gcloud compute instances describe VM_NAME 并在元数据中查找 ssh-keys 字段。

    如需解决此问题,请从实例元数据中删除每个实例的 SSH 密钥

排查 Konnectivity 代理问题

您可以通过检查以下系统 Deployment 来确定集群是否使用 Konnectivity 代理:

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

Konnectivity 代理的问题可能是由以下原因造成的:

  • 您的网络的防火墙规则不允许 Konnectivity 代理访问控制平面。

    在创建集群时,Konnectivity 代理 Pod 会在端口 8132 上建立并维护与控制平面的连接。运行其中一个 kubectl 命令时,API 服务器会使用此连接与集群进行通信。

    如果您的网络的防火墙规则包含出站流量拒绝规则,则可能会阻止代理建立连接。

    如需验证问题是否由此原因引起,请检查网络的防火墙规则,看看它们是否包含出站流量拒绝规则。

    如需解决此问题,请允许出站流量通过端口 8132 进入集群控制平面。(相比之下,API 服务器使用 443)。

  • 您的集群的网络政策会阻止从 kube-system 命名空间到 workload 命名空间的入站流量。

    集群的正确运行并不需要这些功能。如果您希望集群的网络拒绝所有外部访问,请注意这些功能将停止工作。

    如需验证问题是否由此原因引起,请通过运行以下命令查找受影响命名空间中的网络政策:

    kubectl get networkpolicy --namespace AFFECTED_NAMESPACE
    

    如需解决此问题,请将以下内容添加到网络政策的 spec.ingress 字段中:

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

排查错误 4xx 问题

以下部分可帮助您排查错误 400、401、403、404 以及相关的身份验证和授权错误。

问题:连接到 GKE 集群时出现身份验证和授权错误

连接到 GKE 集群时,您可能会收到 HTTP 状态代码为 401(未经授权)的身份验证和授权错误。如果您尝试在本地环境的 GKE 集群中运行 kubectl 命令,可能会出现此问题。

此问题可能是由以下某种原因造成的:

  • gke-gcloud-auth-plugin 身份验证插件未正确安装或配置。
  • 您无权连接到集群 API 服务器并运行 kubectl 命令。

如需诊断原因,请按照以下部分中的步骤操作:

  1. 使用 curl 连接到集群
  2. 在 kubeconfig 中配置插件

使用 curl 连接到集群

如需诊断身份验证和授权错误的原因,请使用 curl 连接到集群。使用 curl 可绕过 kubectl CLI 和 gke-gcloud-auth-plugin 插件。

  1. 设置环境变量:

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. 验证您的访问令牌是否有效:

    curl https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN
    
  3. 尝试连接到 API 服务器中的核心 API 端点:

    gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(masterAuth.clusterCaCertificate)" | base64 -d > /tmp/ca.crt
    curl -s -X GET "${APISERVER}/api/v1/namespaces" --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
    

    如果 curl 命令成功,请按照在 kubeconfig 中配置插件部分中的步骤检查插件是否是原因。

    如果 curl 命令失败,并且输出类似于以下内容,则表示您没有正确的权限来访问集群:

    {
    "kind": "Status",
    "apiVersion": "v1",
    "metadata": {},
    "status": "Failure",
    "message": "Unauthorized",
    "reason": "Unauthorized",
    "code": 401
    }
    

如需解决此问题,请获取正确的权限来访问集群。

在 kubeconfig 中配置插件的使用

如果您在连接到集群时收到身份验证和授权错误,但能够使用 curl 连接到集群,请确保您无需 gke-gcloud-auth-plugin 插件即可访问集群。

如需解决此问题,请将您的本地环境配置为在向集群进行身份验证时忽略 gke-gcloud-auth-plugin 二进制文件。在运行 1.25 版及更高版本的 Kubernetes 客户端中,gke-gcloud-auth-plugin 二进制文件是必需的,因此您需要使用 kubectl CLI 1.24 版或更低版本。

请按照以下步骤操作,以便在无需插件的情况下即可访问集群:

  1. 使用 curl 安装 kubectl CLI 1.24 版:

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    

    您可以使用任何 kubectl CLI 1.24 版或更低版本。

  2. 在文本编辑器中打开 shell 启动脚本文件,例如对于 Bash shell 为 .bashrc

    vi ~/.bashrc
    

    如果您使用的是 MacOS,请在这些指令中使用 ~/.bash_profile 而不是 .bashrc

  3. 将以下行添加到文件中并保存:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. 运行启动脚本:

    source ~/.bashrc
    
  5. 获取集群的凭据,以设置 .kube/config 文件:

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

    替换以下内容:

  6. 运行 kubectl 命令:

    kubectl cluster-info
    

如果您在运行这些命令时收到 401 错误或类似的授权错误,请确保您拥有正确的权限,然后重新运行返回错误的步骤。

错误 400:节点池需要重新创建

错误 400“节点池需要重新创建”类似于以下内容:

  ERROR: (gcloud.container.clusters.update) ResponseError: code=400, message=Node pool "test-pool-1" requires recreation.

当您尝试执行重新创建控制平面和节点的操作时,会发生此错误。例如,当您完成正在进行的凭据变换时,可能会发生此错误。

在后端,节点池会标记为要进行重新创建,但实际的重新创建操作可能需要一些时间才能开始。因此,该操作会失败,因为 GKE 尚未在集群中重新创建一个或多个节点池。

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

  • 等待重新创建完成。这可能需要几个小时、几天或几周的时间,具体取决于现有维护窗口和排除项等因素。
  • 通过启动与控制平面相同的版本升级,手动开始重新创建受影响的节点池。

    如需开始重新创建,请运行以下命令:

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool=POOL_NAME
    

    升级完成后,请重试该操作。

错误 403:权限不足

错误 403,权限不足,类似于以下内容:

  ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Required "container.clusters.get" permission(s) for "projects/<your-project>/locations/<region>/clusters/<your-cluster>".

当您尝试使用 gcloud container clusters get-credentials 连接到 GKE 集群,但账号无权访问 Kubernetes API 服务器时,会发生此错误:

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

  1. 确定存在访问权限问题的账号:

    gcloud auth list
    
  2. 按照向 Kubernetes API 服务器进行身份验证中的说明,向该账号授予所需的访问权限。

错误 403:重试预算用尽

当您尝试创建 GKE 集群时,会发生以下错误:

Error: googleapi: Error 403: Retry budget exhausted: Google Compute Engine:
Required permission 'PERMISSION_NAME' for 'RESOURCE_NAME'.

在此错误消息中,以下变量适用:

  • PERMISSION_NAME:权限的名称,例如 compute.regions.get
  • RESOURCE_NAME:您尝试访问的 Google Cloud 资源的路径,例如 Compute Engine 区域。

如果关联到集群的 IAM 服务账号没有创建集群所需的最低权限,则会发生此错误。

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

  1. 创建或修改 IAM 服务账号,使其拥有运行 GKE 集群所需的所有权限。如需查看相关说明,请参阅使用最小权限 IAM 服务账号
  2. 使用 --service-account 标志在集群创建命令中指定更新后的 IAM 服务账号。如需查看相关说明,请参阅创建 Autopilot 集群

或者,省略 --service-account 标记,让 GKE 使用项目中的 Compute Engine 默认服务账号,该账号默认具有所需权限。

错误 404:调用 gcloud container 命令时“找不到”资源

如果您在调用 gcloud container 命令时收到错误 403(找不到资源),请通过重新向 Google Cloud CLI 进行身份验证来解决此问题:

  gcloud auth login

错误 400/403:缺少账号的修改权限

缺少账号的修改权限错误(错误 400 或 403)表示以下任一项已被手动删除或修改:

启用 Compute Engine 或 Kubernetes Engine API 时,Google Cloud 会创建以下服务账号和代理:

  • 具有项目的修改权限的 Compute Engine 默认服务账号
  • 具有项目的修改权限的 Google API 服务代理
  • 具有项目的 Kubernetes Engine Service Agent 角色的 Google Kubernetes Engine 服务账号

如果有人在任何时候修改了这些权限、移除了项目的角色绑定、完全移除了服务账号或停用了 API,则集群创建和所有管理功能都将失败。

如需验证 Google Kubernetes Engine 服务账号是否分配了项目的 Kubernetes Engine Service Agent 角色,请执行以下步骤:

  1. 使用以下格式计算 Google Kubernetes Engine 服务账号的名称:

    service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
    

    PROJECT_NUMBER 替换为您的项目编号

  2. 验证您的 Google Kubernetes Engine 服务账号是否尚未分配项目的 Kubernetes Engine Service Agent 角色。在此命令中,将 PROJECT_ID 替换为您的项目 ID:

    gcloud projects get-iam-policy PROJECT_ID
    

如需解决此问题,请按照以下步骤操作:

  • 如果有人从您的 Google Kubernetes Engine 服务账号中移除了 Kubernetes Engine Service Agent 角色,请重新添加该角色。
  • 否则,请按照以下说明重新启用 Kubernetes Engine API,以正确恢复您的服务账号和权限。

控制台

  1. 转到 Google Cloud 控制台中的 API 和服务页面。

    转到“API 和服务”

  2. 选择您的项目。

  3. 点击启用 API 和服务

  4. 搜索 Kubernetes,然后从搜索结果中选择 API。

  5. 点击启用。如果您之前已启用 API,则必须先停用,然后再次启用。API 和相关服务的启用可能需要几分钟才能完成。

gcloud

在 gcloud CLI 中运行以下命令:

PROJECT_NUMBER=$(gcloud projects describe "PROJECT_ID"
    --format 'get(projectNumber)')
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member "serviceAccount:service-${PROJECT_NUMBER?}@container-engine-robot.iam.gserviceaccount.com" \
    --role roles/container.serviceAgent

排查 GKE 集群创建问题

错误 CONDITION_NOT_MET:违反了限制条件 constraints/compute.vmExternalIpAccess

您将组织政策限制条件 constraints/compute.vmExternalIpAccess 配置为 Deny All,或者将外部 IP 限制为您尝试在其中创建公共 GKE 集群的组织、文件夹或项目级层的特定虚拟机实例。

当您创建公共 GKE 集群时,构成该集群的工作器节点的底层 Compute Engine 虚拟机会分配外部 IP 地址。如果您将组织政策限制条件 constraints/compute.vmExternalIpAccess 配置为 Deny All,或者将外部 IP 限制为仅用于特定虚拟机实例,则该政策会阻止 GKE 工作节点获取外部 IP 地址,从而导致集群创建失败。

如需查找集群创建操作的日志,您可以使用 Logs Explorer 以及类似于以下内容的搜索查询来查看 GKE 集群操作审核日志

resource.type="gke_cluster"
logName="projects/test-last-gke-sa/logs/cloudaudit.googleapis.com%2Factivity"
protoPayload.methodName="google.container.v1beta1.ClusterManager.CreateCluster"
resource.labels.cluster_name="CLUSTER_NAME"
resource.labels.project_id="PROJECT_ID"

如需解决此问题,请确保在您尝试创建 GKE 公共集群的项目中,限制条件 constraints/compute.vmExternalIpAccess 的有效政策为 Allow All。如需了解如何使用此限制条件,请参阅将外部 IP 地址限制为仅用于特定虚拟机实例。将限制条件设置为 Allow All 后,请删除失败的集群并创建新集群。这是必需的,因为无法修复失败的集群。

排查已部署工作负载的问题

如果工作负载的 Pod 存在问题,GKE 将返回错误。 您可以使用 kubectl 命令行工具或 Google Cloud 控制台检查 Pod 的状态。

kubectl

如需查看集群中正在运行的所有 Pod,请运行以下命令:

kubectl get pods

输出:

NAME       READY  STATUS             RESTARTS  AGE
POD_NAME   0/1    CrashLoopBackOff   23        8d

如需获取有关特定 Pod 的更多详细信息,请运行以下命令:

kubectl describe pod POD_NAME

POD_NAME 替换为所需 Pod 的名称。

控制台

执行以下步骤:

  1. 进入 Google Cloud 控制台中的工作负载页面。

    进入“工作负载”

  2. 选择工作负载。概览标签页显示工作负载的状态。

  3. 托管 Pod 部分,点击错误状态消息。

以下部分介绍了工作负载返回的一些常见错误以及解决方法。

错误:CrashLoopBackOff

CrashLoopBackOff 表示容器在重新启动后反复崩溃。容器可能由于多种原因而崩溃,通常检查 Pod 的日志即可排除根本原因。

默认情况下,崩溃的容器重新启动,指数延迟限制为五分钟。您可以通过在 spec: restartPolicy 下设置 restartPolicy 字段 Deployment 的 Pod 规范来更改此行为。该字段的默认值为 Always

您可以使用 Google Cloud 控制台排查 CrashLoopBackOff 错误:

  1. 转至崩溃循环的 Pod 交互式 playbook:

    前往 Playbook

  2. 集群部分,输入要进行问题排查的集群的名称。

  3. 命名空间部分,输入要进行问题排查的命名空间。

  4. (可选)创建提醒,以便在日后发生 CrashLoopBackOff 错误时通知您:

    1. 未来应对措施提示部分中,选择创建提醒

检查日志

您可以使用 kubectl 命令行工具或 Google Cloud 控制台找出 Pod 容器崩溃的原因。

kubectl

如需查看集群中正在运行的所有 Pod,请运行以下命令:

kubectl get pods

查找具有 CrashLoopBackOff 错误的 Pod。

如需获取 Pod 的日志,请运行以下命令:

kubectl logs POD_NAME

POD_NAME 替换为有问题的 Pod 的名称。

您还可以传递 -p 标志,以获取 Pod 容器的上一个实例的日志(如果存在)。

控制台

执行以下步骤:

  1. 进入 Google Cloud 控制台中的工作负载页面。

    进入“工作负载”

  2. 选择工作负载。概览标签页显示工作负载的状态。

  3. 托管 Pod 部分中,点击有问题的 Pod。

  4. 在 Pod 的菜单中,点击日志标签页。

检查崩溃容器的“退出代码”

您可以通过执行以下任务找到退出代码:

  1. 运行以下命令:

    kubectl describe pod POD_NAME
    

    POD_NAME 替换为 Pod 的名称。

  2. 查看 containers: CONTAINER_NAME: last state: exit code 字段中的值:

    • 如果退出代码为 1,表示容器因为应用崩溃而崩溃。
    • 如果退出代码为 0,请验证您的应用运行了多长时间。

    当应用的主进程退出时,容器将退出。如果您的应用很快完成执行,容器可能仍会继续重新启动。

连接到正在运行的容器

打开一个连接至 Pod 的 shell:

kubectl exec -it POD_NAME -- /bin/bash

如果您的 Pod 中有多个容器,请添加 -c CONTAINER_NAME

现在,您可以从容器运行 bash 命令:您可以测试网络或检查您是否可以访问应用使用的文件或数据库。

错误 ImagePullBackOff 和 ErrImagePull

ImagePullBackOffErrImagePull 指示无法从映像注册表加载容器使用的映像。

您可以使用 Google Cloud 控制台或 kubectl 命令行工具验证此问题。

kubectl

要获取有关 Pod 容器映像的更多信息,请运行以下命令:

kubectl describe pod POD_NAME

控制台

执行以下步骤:

  1. 进入 Google Cloud 控制台中的工作负载页面。

    进入“工作负载”

  2. 选择工作负载。概览标签页显示工作负载的状态。

  3. 托管 Pod 部分中,点击有问题的 Pod。

  4. 在 Pod 的菜单中,点击事件标签页。

问题:如果找不到映像

如果找不到您的映像:

  1. 验证映像的名称是否正确。
  2. 验证映像的标记正确。(尝试使用 :latest 命令或不添加标记来获取最新映像)。
  3. 如果映像具有完整的注册表路径,请验证它是否存在于您正在使用的 Docker 注册表中。如果仅提供映像名称,请检查 Docker Hub 注册表。
  4. 尝试手动拉取 docker 映像:

    • 使用 SSH 连接到节点:

      例如,如需通过 SSH 连接到虚拟机,请运行以下命令:

      gcloud compute ssh VM_NAME --zone=ZONE_NAME
      

      替换以下内容:

    • 运行 docker-credential-gcr configure-docker。此命令会在 /home/[USER]/.docker/config.json 中生成一个配置文件。确保此文件在 credHelpers 字段中包含映像的注册表。例如,以下文件包含托管在 asia.gcr.io、eu.gcr.io、gcr.io、marketplace.gcr.io 和 us.gcr.io 中的映像的身份验证信息:

      {
        "auths": {},
        "credHelpers": {
          "asia.gcr.io": "gcr",
          "eu.gcr.io": "gcr",
          "gcr.io": "gcr",
          "marketplace.gcr.io": "gcr",
          "us.gcr.io": "gcr"
        }
      }
      
    • 运行 docker pull IMAGE_NAME

    如果此选项有效,则可能需要在 Pod 上指定 ImagePullSecrets。Pod 只能在自己的命名空间中引用映像拉取密钥,因此每个命名空间需要执行一次此过程。

错误:权限遭拒

如果您遇到“权限被拒绝”或“无拉取路径”错误,请确认您已登录并有权访问该映像。根据您托管映像的注册表,尝试以下方法之一。

Artifact Registry

如果您的映像位于 Artifact Registry 中,您的节点池的服务账号需要对包含该映像的代码库拥有读取访问权限。

artifactregistry.reader 角色授予服务账号:

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --location=REPOSITORY_LOCATION \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role="roles/artifactregistry.reader"

替换以下内容:

  • REPOSITORY_NAME:您的 Artifact Registry 代码库的名称。
  • REPOSITORY_LOCATION:您的 Artifact Registry 代码库的区域
  • SERVICE_ACCOUNT_EMAIL:与节点池关联的 IAM 服务账号的电子邮件地址。

Container Registry

如果您的映像位于 Container Registry 中,您的节点池的服务账号需要对包含该映像的 Cloud Storage 存储桶拥有读取访问权限。

roles/storage.objectViewer 角色授予服务账号,以便它可以从存储桶读取数据:

gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role=roles/storage.objectViewer

替换以下内容:

  • SERVICE_ACCOUNT_EMAIL:与节点池关联的服务账号的电子邮件。您可以使用 gcloud iam service-accounts list 列出项目中的所有服务账号。
  • BUCKET_NAME:包含您的映像的 Cloud Storage 存储桶的名称。您可以使用 gcloud storage ls 列出项目中的所有存储桶。

如果您的注册表管理员在 Artifact Registry 中设置 gcr.io 代码库,以存储 gcr.io 网域(而非 Container Registry)的映像,您必须授予对 Artifact Registry(而不是 Container Registry)的读取权限。

私有注册表

如果您的映像位于私有注册表中,您可能需要密钥才能访问映像。如需了解详情,请参阅使用私有注册表

错误 401 未经授权:无法从私有 Container Registry 仓库中拉取映像

从私有 Container Registry 仓库中拉取映像时,可能会发生类似于以下内容的错误:

gcr.io/PROJECT_ID/IMAGE:TAG: rpc error: code = Unknown desc = failed to pull and
unpack image gcr.io/PROJECT_ID/IMAGE:TAG: failed to resolve reference
gcr.io/PROJECT_ID/IMAGE]:TAG: unexpected status code [manifests 1.0]: 401 Unauthorized

Warning  Failed     3m39s (x4 over 5m12s)  kubelet            Error: ErrImagePull
Warning  Failed     3m9s (x6 over 5m12s)   kubelet            Error: ImagePullBackOff
Normal   BackOff    2s (x18 over 5m12s)    kubelet            Back-off pulling image
  1. 确定运行 Pod 的节点:

    kubectl describe pod POD_NAME | grep "Node:"
    
  2. 验证节点是否具有存储范围:

    gcloud compute instances describe NODE_NAME \
        --zone=COMPUTE_ZONE --format="flattened(serviceAccounts[].scopes)"
    

    节点的访问权限范围应至少包含以下一个范围:

    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/devstorage.read_only
    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/cloud-platform
    
  3. 使用足够的范围重新创建节点所属的节点池。您无法修改现有节点,必须使用正确的范围重新创建节点。

    • 推荐:使用 gke-default 范围创建新的节点池:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="gke-default"
      
    • 仅使用存储范围创建新的节点池:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="https://www.googleapis.com/auth/devstorage.read_only"
      

错误:Pod 无法调度

PodUnschedulable 表示由于资源不足或某些配置错误而无法调度 Pod。

如果您已配置您的 GKE 集群,用于将 Kubernetes API 服务器和 Kubernetes 调度器指标发送到 Cloud Monitoring,您可以在调度器指标API 服务器指标中找到有关这些错误的详细信息。

您可以使用 Google Cloud 控制台排查 PodUnschedulable 错误:

  1. 前往无法调度的 Pod 交互式 Playbook:

    前往 Playbook

  2. 集群部分,输入要进行问题排查的集群的名称。

  3. 命名空间部分,输入要进行问题排查的命名空间。

  4. (可选)创建提醒,以便在日后发生 PodUnschedulable 错误时通知您:

    1. 未来应对措施提示部分中,选择创建提醒

错误:资源不足

您可能会遇到指示缺少 CPU、内存或其他资源的错误。例如:“没有可用的节点匹配所有谓词:cpu(2)不足”,表明在两个节点上没有足够的 CPU 可用于满足 Pod 的请求。

如果您的 Pod 资源请求量超过任何符合条件的节点池中单个节点所能提供的资源,则 GKE 不会安排 Pod,也不会触发扩容以添加新节点。要让 GKE 对 Pod 进行安排,您必须为 Pod 请求少量的资源,或者创建具有足够资源的新节点池。

此外,您还可以启用节点自动预配功能,以便 GKE 能够自动创建节点池,这类节点池具有可运行未安排的 Pod 的节点。

默认 CPU 请求是 100M 或 CPU(或一个核心)的 10%。 如果您想请求更多或更少的资源,请在 spec: containers: resources: requests 下的 Pod 规范中指定该值

错误:MatchNodeSelector

MatchNodeSelector 指示没有与 Pod 的标签选择器匹配的节点。

如需验证这一点,请在 spec: nodeSelector 下,检查 Pod 规范中的 nodeSelector 字段指定的标签。

如需查看集群中节点的标签,请运行以下命令:

kubectl get nodes --show-labels

如需将标签附加到节点,请运行以下命令:

kubectl label nodes NODE_NAME LABEL_KEY=LABEL_VALUE

请替换以下内容:

  • NODE_NAME:所需的节点。
  • LABEL_KEY:标签的键。
  • LABEL_VALUE:标签的值。

如需了解详情,请参阅将 Pod 分配给节点

错误:PodToleratesNodeTaints

PodToleratesNodeTaints 指示 Pod 无法调度到任何节点上,因为当前没有节点可容忍其节点污点

如需验证属于这种情况,请运行以下命令:

kubectl describe nodes NODE_NAME

在输出中,选中 Taints 字段,该字段列出了键值对和调度效果。

如果列出的效果是 NoSchedule,则在该节点上没有 Pod 可以计划,除非它有一个匹配的负荷

解决此问题的一种方法是移除污点。例如,如需移除 NoSchedule 污点,请运行以下命令:

kubectl taint nodes NODE_NAME key:NoSchedule-

错误:PodFitsHostPorts

PodFitsHostPorts 指示节点正在尝试使用的端口已在使用中。

如需解决此问题,请在 spec: containers: ports: hostPort 下查看 Pod 规范的 hostPort 值。您可能需要将此值更改为另一个端口。

错误:不具备最低限度的可用性

如果节点有足够的资源但仍然显示 Does not have minimum availability 消息,请查看 Pod 的状态。如果状态为 SchedulingDisabledCordoned 状态,则该节点无法调度新的 Pod。您可以使用 Google Cloud 控制台或 kubectl 命令行工具检查节点的状态。

kubectl

如需获取节点的状态,请运行以下命令:

kubectl get nodes

如需在节点上启用调度,请运行:

kubectl uncordon NODE_NAME

控制台

执行以下步骤:

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 选择集群。节点标签页显示节点及其状态。

如需在节点上启用调度,请执行以下步骤:

  1. 从列表中,点击所需的节点。

  2. 从“节点详细信息”中,点击取消封锁按钮。

错误:已达到每个节点的 Pod 数上限

如果集群中的所有节点都达到每个节点的 Pod 数上限,Pod 会卡在“无法调度”状态。在 Pod 事件标签页下,您会看到包含 Too many pods 字词的消息。

  1. 在 Google Cloud 控制台中,通过 GKE 集群详情中的“节点”标签页查看 Maximum pods per node 配置。

  2. 获取节点列表:

    kubectl get nodes
    
  3. 对于每个节点,请验证在节点上运行的 Pod 数量:

    kubectl get pods -o wide | grep NODE_NAME | wc -l
    
  4. 如果达到了上限,请添加新的节点池,或向现有节点池添加更多节点。

问题:在启用集群自动扩缩器的情况下,已达到节点池大小上限

如果节点池已达到大小上限,根据集群自动扩缩器配置,GKE 不会触发使用此节点池安排的 Pod 纵向扩容。如果您希望使用此节点池调度 Pod,请更改集群自动扩缩器配置

问题:在停用集群自动扩缩器的情况下,已达到节点池大小上限

如果节点池已达到节点数量上限,并且集群自动扩缩器已停用,则 GKE 无法使用节点池调度 Pod。增加节点池的大小启用集群自动扩缩器,以便 GKE 自动调整集群的大小。

错误:PersistentVolumeClaims 未绑定

Unbound PersistentVolumeClaims 指示 Pod 引用了未绑定的 PersistentVolumeClaim。如果您的 PersistentVolume 预配失败,可能会发生此错误。您可以通过获取 PersistentVolumeClaim 事件并检查其是否失败来验证预配是否失败。

如需获取事件,请运行以下命令:

kubectl describe pvc STATEFULSET_NAME-PVC_NAME-0

请替换以下内容:

  • STATEFULSET_NAME:StatefulSet 对象的名称。
  • PVC_NAME:PersistentVolumeClaim 对象的名称。

如果您在手动预配 PersistentVolume 并将其绑定到 PersistentVolumeClaim 期间遇到配置错误,也可能会出现此问题。您可以尝试再次预配卷。

错误:配额不足

验证您的项目是否有足够的 Compute Engine 配额供 GKE 纵向扩容集群。如果 GKE 尝试向集群添加节点以安排 Pod,并且扩容将超出项目的可用配额,则您会收到 scale.up.error.quota.exceeded 错误消息。

如需了解详情,请参阅扩容错误

问题:API 已弃用

确保您没有使用已弃用的 API,这些 API 已与集群的次要版本一起移除。如需了解详情,请参阅 GKE 弃用

错误:“无法为范围 0 分配:没有设置范围内的 IP 地址”

GKE 1.18.17 版及更高版本修复了以下问题:如果在容器启动之前删除了 Pod,则内存不足 (OOM) 事件会导致 Pod 被错误逐出。这种错误的逐出操作可能会导致孤立的 Pod 继续使用分配的节点范围内的预留 IP 地址。随着时间的推移,由于孤立 Pod 逐渐增多,GKE 会用完要分配给新 Pod 的 IP 地址。这导致出现错误消息 failed to allocate for range 0: no IP addresses in range set,因为分配的节点范围没有可用的 IP 分配给新 Pod。

如需解决此问题,请将集群和节点池升级到 GKE 1.18.17 版或更高版本

如需在 GKE 版本在 1.18.17 之前的集群上防止和解决此问题,请提高资源限制以避免将来发生 OOM 事件,然后通过移除孤立的 Pod 来收回 IP 地址。

您还可以查看 GKE IP 地址利用率数据分析

从受影响的节点中移除孤立的 Pod

您可以通过排空节点、升级节点池或移动受影响的目录来移除孤立的 Pod。

排空节点(推荐)

  1. 封锁节点,以防止新 Pod 调度到该节点上:

     kubectl cordon NODE
    

    NODE 替换为您要排空的节点的名称。

  2. 排空节点。 GKE 会自动将部署管理的 Pod 重新调度到其他节点上。使用 --force 标志可排空没有管理资源的孤立 Pod。

     kubectl drain NODE --force
    
  3. 取消封锁节点,以允许 GKE 将新 Pod 调度到该节点上:

     kubectl uncordon NODE
    

移动受影响的目录

您可以识别 /var/lib/kubelet/pods 中孤立的 Pod 目录,并将其移出主目录,以允许 GKE 终止 Pod。

排查终止资源存在的问题

问题:命名空间卡在 Terminating 状态





## Debug GKE Cluster Austoscaler issues with gcpdiag

















  
  

gcpdiag is an open source tool. It is not an officially supported Google Cloud product. You can use the gcpdiag tool to help you identify and fix Google Cloud project issues. For more information, see the gcpdiag project on GitHub.

This gcpdiag runbook investigates potential causes for GKE Cluster Autoscaler failures while performing scale up or scale down operations. It looks for the following error message in logs: <ul> <li><strong>scale.up.error.out.of.resources</strong></li> <li><strong>scale.up.error.quota.exceeded</strong></li> <li><strong>scale.up.error.waiting.for.instances.timeout</strong></li> <li><strong>scale.up.error.ip.space.exhausted</strong></li> <li><strong>scale.up.error.service.account.deleted</strong></li> <li><strong>scale.down.error.failed.to.evict.pods</strong></li> <li><strong>no.scale.down.node.node.group.min.size.reached</strong></li> </ul>

Google Cloud console

  1. Complete and then copy the following command.
  2. gcpdiag runbook gke/cluster-autoscaler --project=<var>PROJECT_ID</var> \\
        --parameter name=<var>CLUSTER_NAME</var> \\
        --parameter location=<var>LOCATION</var>
  3. 打开 Google Cloud 控制台并激活 Cloud Shell。
  4. 打开 Cloud 控制台
  5. 粘贴复制的命令。
  6. 运行 gcpdiag 命令以下载 gcpdiag Docker 映像,然后执行诊断检查。如果适用,请按照输出说明修复失败的检查。
  7. Docker

    您可以使用封装容器运行 gcpdiag,以在 Docker 容器中启动 gcpdiag。必须安装 Docker 或 Podman

    1. 在本地工作站上复制并运行以下命令。
      curl https://gcpdiag.dev/gcpdiag.sh >gcpdiag && chmod +x gcpdiag
    2. 执行 gcpdiag 命令:
      ./gcpdiag runbook gke/cluster-autoscaler --project=<var>PROJECT_ID</var> \\
          --parameter name=<var>CLUSTER_NAME</var> \\
          --parameter location=<var>LOCATION</var>

    查看此 Runbook 的可用参数

    替换以下内容:

    • PROJECT_ID:资源所在项目的 ID
    • <li><var>CLUSTER_NAME</var>:项目中目标 GKE 集群的名称。</li> <li><var>LOCATION</var>:目标 GKE 集群所在的位置(对于可用区级集群,此位置是可用区;对于区域级集群,此位置是区域)。</li>

    实用标志:

    • --projectPROJECT_ID
    • --universe-domain:如果适用,则为托管资源的可信合作伙伴主权云网域
    • --parameter-p:Runbook 参数

    如需查看所有 gcpdiag 工具标志的列表和说明,请参阅 gcpdiag 使用说明

    ## 排查集群中的指标未显示在 Cloud Monitoring 中的问题 {:#no_metrics} 确保您已在项目上 [启用 Monitoring API](/monitoring/api/enable-api) 和 [Logging API](/logging/docs/api/enable-api)。您还应确认您能够在 Google Cloud 控制台的 [Cloud Monitoring 概览](https://console.cloud.google.com/monitoring) 中查看项目。如果问题仍然存在,请检查以下潜在原因: 1. 确保已在集群上启用监控。 对于通过 Google Cloud 控制台和通过 Google Cloud CLI 创建的集群,监控默认处于启用状态,但您可以通过运行以下命令或点击 [Google Cloud 控制台](https://console.cloud.google.com/) 中的集群详细信息进行验证: ```sh gcloud container clusters describe CLUSTER_NAME ``` 此命令的输出应在“monitoringConfig”部分的“enableComponents”列表中包含“SYSTEM_COMPONENTS”,类似于以下内容: ``` monitoringConfig: componentConfig: enableComponents: - SYSTEM_COMPONENTS ``` 如果未启用监控,请运行以下命令启用: ```sh gcloud container clusters update CLUSTER_NAME --monitoring=SYSTEM ``` 1. 自创建集群或启用其监控功能以来已经有多长时间了? 新集群的指标最多可能需要一个小时才能出现在 Cloud Monitoring 中。 1. “kube-system”命名空间的集群中是否正在运行“heapster”或“gke-metrics-agent”(OpenTelemetry 收集器)?此 Pod 可能无法调度工作负载,因为您的集群没有足够资源。通过调用“kubectl get pods --namespace=kube-system”并检查名称中带有“heapster”或“gke-metrics-agent”的 Pod,检查 Heapster 或 OpenTelemetry 是否正在运行。1. 集群的控制层面是否能够与节点通信? Cloud Monitoring 以此为基础。您可以通过运行以下命令来确认是否存在这种情况: ``sh kubectl logs POD_NAME ``` 如果此命令返回错误,则问题可能是 SSH 隧道导致的。如需了解详情,请参阅 [此部分](/kubernetes-engine/docs/troubleshooting#kubect_commands_stops)。如果您遇到与 Cloud Logging 代理相关的问题,请参阅其 [问题排查文档]。如需了解详情,请参阅 [Logging 文档](/logging/docs/)。## 问题:集群的根证书授权机构即将过期 {:#ca_expiring} 集群的根证书授权机构即将过期。为防止正常的集群操作中断,您必须执行 [凭据变换](/kubernetes-engine/docs/how-to/credential-rotation)。## 错误:“实例‘Foo’不包含‘instance-template’元数据”{:#instance-template-missing} 如果节点池的状态无法升级、扩缩或执行自动节点修复,您可能会看到“实例‘Foo’不包含‘instance-template’元数据”错误。此消息表示由 GKE 分配的虚拟机实例的元数据已损坏。这种情况通常发生在自定义编写的自动化功能或脚本尝试添加新的实例元数据(例如 [`block-project-ssh-keys`](/compute/docs/connect/restrict-ssh-keys#block-keys))时,不仅会添加或更新值,还会删除现有元数据。您可以在 [设置自定义元数据](/compute/docs/storing-retrieving-metadata#custom) 中了解虚拟机实例元数据。如果删除了任何关键元数据值(以及其他值:“instance-template”“kube-labels”“kubelet-config”“kubeconfig”“cluster-name”“configure-sh”“cluster-uid”),则节点或整个节点池可能会自行呈现不稳定状态,因为这些值对于 GKE 操作至关重要。 如果实例元数据已损坏,则恢复元数据的最佳方式是重新创建包含损坏的虚拟机实例的节点池。您需要向集群 [添加节点池](/kubernetes-engine/docs/how-to/node-pools#add),并增加新节点池中的节点数,同时封锁并移除其他节点池中的节点。请参阅 [在节点池之间迁移工作负载](/kubernetes-engine/docs/troubleshooting/troubleshoot-node-pools#migrate-node-pools) 的说明。 如需了解实例元数据的修改者和修改时间,您可以查看 [Compute Engine 审核日志记录信息](/compute/docs/logging/audit-logging),也可以使用 [Logs Explorer](/logging/docs/view/logs-explorer-interface) 以及类似于以下内容的搜索查询来查找日志: ```none resource.type="gce_instance_group_manager" protoPayload.methodName="v1.compute.instanceGroupManagers.setInstanceTemplate" ``` 在日志中,您可以找到请求发起者 IP 地址和用户代理: ``` json requestMetadata: { callerIp: "REDACTED" callerSuppliedUserAgent: "google-api-go-client/0.5 GoogleContainerEngine/v1" } ``` 如需详细了解 GKE 中的 Secret,请参阅 [在应用层加密 Secret](/kubernetes-engine/docs/how-to/encrypting-secrets)。## 问题:Secret 加密更新失败 {:#secrets_encryption_update_failed} 如果启用、停用或更新 [Cloud KMS 密钥](/kubernetes-engine/docs/how-to/encrypting-secrets) 的操作失败,请参阅 [排查应用层 Secret 加密问题](/kubernetes-engine/docs/troubleshooting/troubleshoot-secrets) 指南。