排查 GKE Ingress 问题

Google Kubernetes Engine (GKE) 中的 Ingress 问题可能会阻止外部或内部流量到达您的服务。

您可参考本文档,找到与 Ingress 类、静态 IP 注解、证书密钥大小以及与网络层级交互相关的错误的解决方案。

此信息适用于在 GKE 中部署和管理使用 Ingress 公开的应用的平台管理员、运维人员和应用开发者。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务

Ingress 类的注解不正确

症状

创建 Ingress 时,您可能会看到以下错误:

Missing one or more resources. If resource creation takes longer than expected, you might have an invalid configuration.

潜在原因

创建 Ingress 时,您可能在清单中错误地配置了 Ingress 类。

解决方法

如需指定 Ingress 类,您必须使用 kubernetes.io/ingress.class 注解。您不能使用 spec.ingressClassName 指定 GKE Ingress。

  • 如需部署内部应用负载均衡器,请使用 kubernetes.io/ingress.class: gce-internal 注解。
  • 如需部署外部应用负载均衡器,请使用 kubernetes.io/ingress.class: gce 注解。

静态 IP 地址的注解不正确

症状

将外部 Ingress 配置为使用静态 IP 地址时,您可能会看到以下错误:

Error syncing to GCP: error running load balancer syncing routine: loadbalancer <Name of load balancer> does not exist: the given static IP name <Static IP> doesn't translate to an existing static IP.

潜在原因

  • 您在部署 Ingress 之前未创建静态外部 IP 地址。
  • 您没有为负载均衡器类型使用正确的注解。

解决方法

如果您要配置内部 Ingress,请执行以下操作:

  • 在部署 Ingress 之前,预留静态外部 IP 地址
  • 在 Ingress 资源上使用 kubernetes.io/ingress.global-static-ip-name 注解。

如果您要配置内部 Ingress,请执行以下操作:

  • 在部署 Ingress 之前,预留区域级静态内部 IP 地址。
  • 在 Ingress 资源上使用 kubernetes.io/ingress.regional-static-ip-name 注解。

静态 IP 地址已被使用

症状

当您指定静态 IP 地址来预配内部或外部 Ingress 资源时,可能会看到以下错误:

Error syncing to GCP: error running load balancer syncing
routine: loadbalancer <LB name> does not exist:
googleapi: Error 409: IP_IN_USE_BY_ANOTHER_RESOURCE - IP ''<IP address>'' is already being used by another resource.

潜在原因

该静态 IP 地址已被其他资源使用。

停用 HTTP 并使用 Google 管理的证书时出错

症状

如果您要配置 Google 管理的 SSL 证书并在 Ingress 上停用 HTTP 流量,则会看到以下错误:

Error syncing to GCP: error running load balancer syncing
routine: loadbalancer <Load Balancer name> does not exist:
googleapi: Error 404: The resource ''projects/<Project>/global/sslPolicies/<Policy name>' was not found, notFound

潜在原因

配置 Ingress 时,您不能同时使用以下注解:

  • networking.gke.io/managed-certificates(用于将 Google 管理的证书与 Ingress 相关联)
  • kubernetes.io/ingress.allow-http: false(用于停用 HTTP 流量)

解决方法

仅在外部应用负载均衡器完全编程后才停用 HTTP 流量。您可以更新 Ingress 并将注解 kubernetes.io/ingress.allow-http: false 添加到清单中。

内部 Ingress 缺少代理专用子网

症状

为内部应用负载均衡器部署 Ingress 时,您可能会看到以下错误:

Error syncing to GCP: error running load balancer syncing routine:
loadbalancer <LB name> does not exist: googleapi: Error 400: Invalid value for field 'resource.target': 'https://www.googleapis.com/compute/v1/projects/<Project ID>/regions/<Region>/targetHttpsProxies/<Target proxy>'.
An active proxy-only subnetwork is required in the same region and VPC as
the forwarding rule.

潜在原因

您在创建 Ingress 资源之前未创建代理专用子网。对于内部应用负载均衡器,代理专用子网是必需的。

解决方法

在部署内部 Ingress 之前,创建代理专用子网

SSL 证书密钥过大

症状

如果负载均衡器的 SSL 证书的密钥大小过大,您可能会看到以下错误:

Error syncing to GCP: error running load balancer syncing routine: loadbalancer gky76k70-load-test-trillian-api-ingress-fliismmb does not exist: Cert creation failures - k8s2-cr-gky76k70-znz6o1pfu3tfrguy-f9be3a4abbe573f7 Error:googleapi: Error 400: The SSL key is too large., sslCertificateKeyTooLarge

潜在原因

Google Cloud 对 SSL 证书密钥的长度的限制为 2,048 位。

解决方法

将 SSL 证书密钥的大小减小到 2,048 位或以下。

在标准层级中创建 Ingress 时出错

症状

如果您在将项目默认网络层级设置为标准的项目中部署 Ingress,系统会显示以下错误消息:

Error syncing to GCP: error running load balancer syncing routine: load balancer <LB Name> does not exist: googleapi: Error 400: STANDARD network tier (the project''s default network tier) is not supported: STANDARD network tier is not supported for global forwarding rule., badRequest

解决方法

将项目默认网络层级配置为高级。

预期 k8s-ingress-svc-acct-permission-check-probe 的“未找到”错误

Ingress 控制器通过从 Google Cloud 项目中提取测试资源,定期检查服务账号权限。这会显示为 GET 名称为 k8s-ingress-svc-acct-permission-check-probe 的(不存在)全球 BackendService。由于此资源通常不应存在,因此 GET 请求将返回“找不到”。这是预期结果;控制器正在检查 API 调用是否因为授权问题而未遭拒。如果您创建了同名的 BackendService,则 GET 会成功,而不是返回“找不到”。

使用容器原生负载均衡时出现的错误

请使用以下技巧验证您的网络配置。以下几个部分说明如何解决与容器原生负载均衡相关的具体问题。

  • 如需了解如何列出您的网络端点组,请参阅负载均衡文档

  • 您可以在服务的 neg-status 注释中找到与服务对应的 NEG 的名称和地区。请使用以下命令获取 Service 规范:

    kubectl get svc SVC_NAME -o yaml
    

    metadata:annotations:cloud.google.com/neg-status 注释列出了服务的对应 NEG 的名称和地区。

  • 您可以使用以下命令检查与 NEG 相对应的后端服务的运行状况:

    gcloud compute backend-services --project PROJECT_NAME \
        get-health BACKEND_SERVICE_NAME --global
    

    后端服务的名称与其 NEG 的名称相同。

  • 如需输出服务的事件日志,请运行以下命令:

    kubectl describe svc SERVICE_NAME
    

    服务的名称字符串包含相应 GKE Service 的名称和命名空间。

无法使用别名 IP 地址创建集群

表现

当您尝试使用别名 IP 地址创建集群时,可能会遇到以下错误:

ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
潜在原因

如果您尝试使用别名 IP 创建的集群同时也使用旧版网络,则会遇到此错误。

解决方法

确保未在同时启用别名 IP 和旧版网络的情况下创建集群。如需详细了解如何使用别名 IP,请参阅创建 VPC 原生集群

流量未到达端点

表现
502/503 错误或连接遭拒错误。
潜在原因

将新端点连接到负载均衡器后,只要新端点响应健康检查,通常就可以访问新端点。如果流量无法到达端点,您可能会遇到 502 错误或连接遭拒错误。

502 错误和连接遭拒错误也可能是由不处理 SIGTERM 的容器引起的。如果容器未明确处理 SIGTERM,则会立即终止并停止处理请求。负载均衡器会继续将传入的流量发送到已终止的容器,从而导致错误。

容器原生负载均衡器只有一个后端端点。在滚动更新期间,旧端点会在新端点编程之前进行去编程。

预配容器原生负载均衡器后,后端 pod 首次部署到新可用区中。当可用区中至少有一个端点时,负载均衡器基础架构会在可用区中进行编程。将新端点添加到可用区时,负载均衡器基础架构会进行编程并导致服务中断。

解决方法

将容器配置为处理 SIGTERM 并在整个终止宽限期(默认为 30 秒)内继续响应请求。将 Pod 配置为在收到 SIGTERM 时开始让健康检查失败。这样可以通知负载均衡器在端点注销正在进行期间停止向 Pod 发送流量。

如果您的应用在收到 SIGTERM 后没有正常关闭并停止响应请求,则可以使用 preStop 钩子来处理 SIGTERM,并在端点注销正在进行期间继续处理流量。

lifecycle:
  preStop:
    exec:
      # if SIGTERM triggers a quick exit; keep serving traffic instead
      command: ["sleep","60"]

请参阅有关 Pod 终止的文档

如果您的负载均衡器后端只有一个实例,请配置发布策略,以避免在新实例完全编程之前删除唯一实例。对于 Deployment 工作负载管理的应用 Pod,可以通过配置发布策略并将 maxUnavailable 参数设置为 0 来实现。

strategy:
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

如需排查流量无法到达端点的问题,请验证防火墙规则是否允许传入的 TCP 流量传输到 130.211.0.0/2235.191.0.0/16 范围内的端点。如需了解详情,请参阅 Cloud Load Balancing 文档中的添加健康检查

查看项目中的后端服务。相关后端服务的名称字符串包含相应 GKE Service 的名称和命名空间:

gcloud compute backend-services list

从后端服务检索后端运行状况:

gcloud compute backend-services get-health BACKEND_SERVICE_NAME

如果所有后端的运行状况都不佳,则防火墙、Ingress 或 Service 可能配置错误。

如果某些后端在短时间内运行状况不佳,则可能是网络编程延迟的原因。

如果某些后端未出现在后端服务列表中,则可能是编程延迟的原因。您可以通过运行以下命令来验证这一点,其中 NEG_NAME 是后端服务的名称。 (NEG 和后端服务共用同一个名称):

gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME

检查所有预期的端点是否都在 NEG 中。

如果容器原生负载均衡器选择了少量后端(例如 1 个 Pod),请考虑增加副本数量并将后端 Pod 分布到 GKE 集群跨越的所有可用区中。这会确保底层负载均衡器基础架构经过完全编程。否则,请考虑将后端 Pod 限制在单个可用区。

如果您为端点配置网络政策,请确保允许来自代理专用子网的入站流量。

停止发布

表现
发布更新 Deployment 的操作处于停止状态,并且最新副本的数量与所选的副本数量不一致。
潜在原因

部署的健康检查失败。容器映像可能已损坏,或者健康检查的配置可能有误。Pod 的滚动替换正在等待新启动的 Pod 通过其 Pod 就绪性门控。仅当 Pod 正在响应负载均衡器健康检查时,才会出现这种情况。如果 Pod 没有响应,或者健康检查的配置有误,则无法满足就绪性门控条件,并且无法继续发布。

如果您使用的是 kubectl 1.13 或更高版本,则可以使用以下命令检查 Pod 的就绪性门控状态:

kubectl get pod POD_NAME -o wide

检查 READINESS GATES 列。

kubectl 1.12 及更低版本中不存在此列。标记为 READY 状态的 Pod 的就绪性门控可能已失败。如需就此进行验证,请使用以下命令:

kubectl get pod POD_NAME -o yaml

输出中会列出就绪性门控及其状态。

解决方法

验证 Deployment 的 Pod 规范中的容器映像是否正常运行,以及是否能够响应健康检查。验证健康检查是否已正确配置。

降级模式错误

表现

从 GKE 1.29.2-gke.1643000 版开始,当 NEG 更新时,您可能会在 Logs Explorer 中收到有关服务的以下警告:

Entering degraded mode for NEG <service-namespace>/<service-name>-<neg-name>... due to sync err: endpoint has missing nodeName field
潜在原因

这些警告表明,GKE 在基于 EndpointSlice 对象的 NEG 更新期间检测到端点错误配置,从而触发了称为降级模式的更深入的计算过程。GKE 会继续尽量更新 NEG,方法是更正错误配置或从 NEG 更新中排除无效端点。

一些常见错误包括:

  • endpoint has missing pod/nodeName field
  • endpoint corresponds to an non-existing pod/node
  • endpoint information for attach/detach operation is incorrect
解决方法

通常,临时状态会导致这些事件,它们会自行解决。不过,由自定义 EndpointSlice 对象中的错误配置导致的事件仍未解决。如需了解错误配置,请检查与服务对应的 EndpointSlice 对象:

kubectl get endpointslice -l kubernetes.io/service-name=<service-name>

根据事件中的错误验证每个端点。

如需解决此问题,您必须手动修改 EndpointSlice 对象。 此更新会触发 NEG 再次更新。配置错误不再存在后,输出类似于以下内容:

NEG <service-namespace>/<service-name>-<neg-name>... is no longer in degraded mode

使用 Google 管理的 SSL 证书时出现的错误

本部分介绍了如何解决由 Google 管理的证书的相关问题。

检查 ManagedCertificate 和 Ingress 资源上的事件

如果您超出了允许的证书数量,则系统将向 ManagedCertificate 添加一个原因为 TooManyCertificates 的事件。您可以使用以下命令检查 ManagedCertificate 对象上的事件:

kubectl describe managedcertificate CERTIFICATE_NAME

CERTIFICATE_NAME 替换为 ManagedCertificate 的名称。

如果您将不存在的 ManagedCertificate 关联到 Ingress,则系统将向 Ingress 添加一个原因为 MissingCertificate 的事件。您可以使用以下命令检查 Ingress 资源上的事件:

kubectl describe ingress INGRESS_NAME

INGRESS_NAME 替换为您的 Ingress 名称。

网域解析为多个负载均衡器的 IP 地址时未预配托管式证书

当网域解析为多个负载均衡器(多个 Ingress 对象)的 IP 地址时,您应该创建一个 ManagedCertificate 对象并将其关联到所有 Ingress 对象。如果您改为创建多个 ManagedCertificate 对象并将每个对象关联到单独的 Ingress,则证书授权机构可能无法验证网域的所有权,并且部分证书可能无法预配。若要使验证成功,证书必须在网域解析为的所有 IP 地址下显示。

具体而言,当您的网域解析为使用不同 Ingress 对象配置的 IPv4 和 IPv6 地址时,您应该创建一个 ManagedCertificate 对象并将其关联到两个 Ingress。

由 Google 管理的证书与 Ingress 之间的通信中断

代管式证书使用 ingress.gcp.kubernetes.io/pre-shared-cert 注解与 Ingress 通信。您可以在以下情况下中断此通信,例如:

  • 运行可清除 ingress.gcp.kubernetes.io/pre-shared-cert 注解的自动化进程。
  • 存储 Ingress 的快照,然后通过快照删除和恢复 Ingress。在此期间,ingress.gcp.kubernetes.io/pre-shared-cert 注解中列出的 SslCertificate 资源可能已被删除。如果缺失关联的任何证书,Ingress 将不起作用。

如果由 Google 管理的证书与 Ingress 之间的通信中断,请删除 ingress.gcp.kubernetes.io/pre-shared-cert 注解的内容并等待系统调节。为防止重复发生,请确保该注解不会被无意中修改或删除。

创建由 Google 管理的证书时出现验证错误

ManagedCertificate 定义会在创建 ManagedCertificate 对象之前验证。如果验证失败,则不会创建 ManagedCertificate 对象并输出错误消息。下面解释了不同的错误消息和原因:

spec.domains in body should have at most 100 items

ManagedCertificate 清单在 spec.domains 字段中列出了超过 100 个网域。由 Google 管理的证书最多只支持 100 个网域。

spec.domains in body should match '^(([a-zA-Z0-9]+|[a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9])\.)+[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]\.?$'

您在 spec.domains 字段中指定的域名或通配符域名无效。ManagedCertificate 对象不支持通配符网域(例如 *.example.com)。

spec.domains in body should be at most 63 chars long

您指定的域名太长。由 Google 管理的证书支持的域名长度最多为 63 个字符。

手动更新由 Google 管理的证书

如需手动更新证书,以便旧网域的证书继续正常运作,直到预配新网域的证书,请按照以下步骤操作:

  1. 为新网域创建 ManagedCertificate
  2. 使用英文逗号分隔列表,将 ManagedCertificate 的名称添加到 Ingress 上的 networking.gke.io/managed-certificates 注释。请勿移除旧证书名称。
  3. 等待 ManagedCertificate 变为活动状态。
  4. 从 Ingress 中分离旧证书并将其删除。

创建 ManagedCertificate 时, Google Cloud 会创建一个 Google 管理的 SSL 证书。您无法更新此证书。 如果您更新 ManagedCertificate,则 Google Cloud 会删除并重新创建 Google 管理的 SSL 证书。

如需为您的 GKE 集群提供安全的 HTTPS 加密 Ingress,请参阅安全 Ingress 示例。

后续步骤