排查 GKE 中的网络隔离问题

Google Kubernetes Engine (GKE) 中的网络隔离配置不正确可能会导致集群创建超时、节点注册失败、控制平面无法访问或无法拉取映像等问题。

本文档可帮助您排查控制平面访问、CIDR 范围重叠、从公共代码库拉取映像时出错等问题,以及与 VPC 网络对等互连或 Private Service Connect 相关的问题。

对于负责配置和管理网络隔离型 GKE 集群以满足安全性和合规性要求的平台管理员、运维人员和网络管理员,此信息非常重要。如需详细了解我们在Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务

GKE 集群未运行

如果删除允许入站流量从集群控制平面传输到端口 10250 上的节点的防火墙规则,或者删除通往默认互联网网关的默认路由,则会导致集群停止运行。如果您删除默认路由,则必须确保将流量路由到必要的Google Cloud 服务。如需了解详情,请参阅自定义路由

创建集群时超时

表现
在 1.28 版或更低版本中使用专用节点创建的集群需要 VPC 之间存在对等互连路由。但是,一次只能进行一项对等互联操作。如果您尝试同时创建多个具有上述特征的集群,则创建集群的操作可能会超时。
解决方法

请使用以下任一解决方案:

  • 依次创建 1.28 版或更低版本的集群,以便每个后续集群都已存在 VPC 对等互连路由,而无需外部端点。如果 VPC 上有操作正在运行,则尝试创建单个集群的操作也可能会超时。

  • 创建 1.29 版或更高版本的集群。

VPC 网络对等互连连接意外删除

表现

如果您不小心删除了 VPC 网络对等互连连接,集群会进入修复状态,并且所有节点都显示 UNKNOWN 状态。由于无法到达控制平面,因此您将无法对集群执行任何操作。检查控制平面时,日志会显示如下所示的错误:

error checking if node NODE_NAME is shutdown: unimplemented
潜在原因

您不小心删除了 VPC 网络对等互连连接。

解决方法

  1. 创建采用 PSC 切换之前的版本及其特定配置的新 GKE 集群。强制重新创建 VPC 对等互连连接时必需执行此操作,这样可使旧集群恢复为正常运行。
    • 为新集群使用以下特定配置:
      • 发布渠道:扩展
      • 集群版本:低于 1.29 的版本,例如 1.28.15-gke.2403000
      • 主 IPv4 CIDR:特定 IP 地址范围,例如 --master-ipv4-cidr=172.16.0.192/28
  2. 监控原始集群状态。
    • 创建新集群(从而重新建立 VPC 对等互连)后,原始集群应从修复状态恢复,其节点应恢复为 Ready 状态。
  3. 删除临时创建的 GKE 集群。
    • 原始集群完全恢复并正常运行后,您可以删除临时创建的 GKE 集群。

Private Service Connect 端点和转发规则意外删除

表现

如果您意外删除了 Private Service Connect 端点或转发规则,集群会进入修复状态,并且所有节点都显示 UNKNOWN 状态。由于无法访问控制平面,因此您将无法对集群执行任何操作。检查控制平面时,日志会显示如下所示的错误:

error checking if node NODE_NAME is shutdown: unimplemented
潜在原因

您意外删除了 Private Service Connect 端点或转发规则。这两项资源都名为 gke-[cluster-name]-[cluster-hash:8]-[uuid:8]-pe,允许控制平面和节点以私密方式连接。

解决方法

轮替控制平面 IP 地址

集群与活动对等互连重叠

表现

如果尝试创建没有外部端点的集群,系统会返回类似于以下内容的错误:

Google Compute Engine: An IP range in the peer network overlaps with an IP
range in an active peer of the local network.
潜在原因

您选择了重叠的控制平面 CIDR。

解决方法

请使用以下任一解决方案:

  • 删除集群,然后使用其他控制平面 CIDR 重新创建集群。
  • 在 1.29 版中重新创建集群,并添加 --enable-private-nodes 标志。

无法访问没有外部端点的集群的控制平面

通过实现任一集群端点访问配置,提高集群控制平面的可达性。如需了解详情,请参阅集群端点访问权限

表现

创建没有外部端点的集群后,如果尝试针对集群运行 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 无法与集群控制平面通信。

解决方法

请使用以下任一解决方案:

  • 启用 DNS 访问权限,以简化的方式安全访问集群。如需了解详情,请参阅基于 DNS 的端点

  • 验证是否已为 kubeconfig 生成集群的凭据或已激活正确的上下文。如需详细了解如何设置集群凭据,请参阅生成 kubeconfig 条目

  • 验证是否允许使用基于 IP 的外部端点访问控制平面。停用对集群控制平面的外部访问权限会将集群与互联网隔离开来。使用此配置时,只有已获授权的内部网络 CIDR 范围或预留的网络有权访问控制平面。

    1. 验证来源 IP 地址是否已获授权访问控制平面:

        gcloud container clusters describe CLUSTER_NAME \
            --format="value(controlPlaneEndpointsConfig.ipEndpointsConfig.authorizedNetworksConfig)"\
            --location=COMPUTE_LOCATION
      

      替换以下内容:

      如果来源 IP 地址未获得授权,则输出可能会返回空结果(只有大括号)或不包含来源 IP 地址的 CIDR 范围

      cidrBlocks:
        cidrBlock: 10.XXX.X.XX/32
        displayName: jumphost
        cidrBlock: 35.XXX.XXX.XX/32
        displayName: cloud shell
      enabled: true
      
    2. 添加已获授权的网络以访问控制平面。

  • 如果您从本地环境或与集群位置不同的区域运行 kubectl 命令,请确保已启用控制平面专用端点全球访问权限。如需了解详情,请参阅使用控制平面的内部 IP 地址从任何区域访问

    1. 描述集群以查看主服务器访问配置响应:

      gcloud container clusters describe CLUSTER_NAME \
          --location=COMPUTE_LOCATION \
          --flatten "controlPlaneEndpointsConfig.ipEndpointsConfig.globalAccess"
      

      替换以下内容:

      成功的输出内容类似如下:

        enabled: true
      
    2. 如果返回 null,请启用使用控制平面的内部 IP 地址从任何区域访问的功能

由于 IPv4 CIDR 块重叠而无法创建集群

表现

gcloud container clusters create 会返回如下所示的错误:

The given master_ipv4_cidr 10.128.0.0/28 overlaps with an existing network
10.128.0.0/20.
潜在原因

您指定了一个与 VPC 中现有子网重叠的控制平面 CIDR 地址块。

解决方法

--master-ipv4-cidr 指定一个与现有子网不重叠的 CIDR 块。

由于服务范围已被其他集群使用,因此无法创建集群

表现

如果尝试创建集群,则系统会返回类似于以下内容的错误:

Services range [ALIAS_IP_RANGE] in network [VPC_NETWORK], subnetwork
[SUBNET_NAME] is already used by another cluster.
潜在原因

以下配置可能会导致此错误:

  • 您选择的服务范围正在被其他集群使用,或者该集群并未删除。
  • 某个集群正在使用这个已删除的服务范围,但备用范围元数据未正确清理。GKE 集群的备用范围保存在 Compute Engine 元数据中,应该在删除集群后移除。即使集群已成功删除,元数据也可能未被移除。
解决方法

请按照以下步骤操作:

  1. 检查现有集群是否正在使用该服务范围。您可以将 gcloud container clusters list 命令与 filter 标志结合使用以搜索集群。如果存在正在使用该服务范围的现有集群,则必须删除该集群或创建新的服务范围。
  2. 如果现有集群未使用该服务范围,请手动移除与您要使用的服务范围匹配的元数据条目

无法创建子网

表现

当您尝试创建具有自动子网的集群或者尝试创建自定义子网时,您可能会遇到以下任一错误:

An IP range in the peer network overlaps
with an IP range in one of the active peers of the local network.
Error: Error waiting for creating GKE cluster: Invalid value for field
PrivateClusterConfig.MasterIpv4CidrBlock: x.x.x.x/28 conflicts with an
existing subnet in one of the peered VPCs.
潜在原因

您指定的控制平面 CIDR 范围与集群中的其他 IP 范围重叠。如果您尝试重复使用最近删除的集群中使用的 master-ipv4-cidr CIDR,也可能会发生此子网创建错误。

解决方法

尝试使用其他 CIDR 范围。

无法从公共 Docker Hub 中拉取映像

表现

集群中运行的 Pod 在 kubectl describe 中显示警告:

Failed to pull image: rpc error: code = Unknown desc = Error response
from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
while waiting for connection (Client.Timeout exceeded while awaiting
headers)
潜在原因

具有专用 IP 地址的节点只需进行额外配置,即可满足互联网访问要求。但是,如果您已启用专用 Google 访问通道并满足其网络要求,则节点可以访问 Google Cloud API 和服务(包括 Artifact Registry)。

解决方法

请使用以下任一解决方案:

  • 将集群中的映像从 Docker Hub 复制到 Artifact Registry。如需了解详情,请参阅从第三方注册表迁移容器

  • GKE 会自动检查 mirror.gcr.io 中是否存在经常访问的 Docker Hub 映像的已缓存副本。

  • 如果必须从 Docker Hub 或其他公共代码库拉取映像,请使用 Cloud NAT 或基于实例的代理(即静态 0.0.0.0/0 路由的目标)。

无法创建新的外部 Webhook

当您尝试创建使用 clientConfig.url 字段来联系集群外部的网络钩子服务器的 ValidatingWebhookConfigurations 或 MutatingWebhookConfigurations 时,会发生以下错误:

ValidatingAdmissionPolicy 'gke-restrict-webhook-url' denied request: Egress
traffic from the API server through the control plane is disabled. As a result,
direct API server calls to external webhook servers are blocked. To connect to
external webhooks, update any webhook configurations that use clientConfig.url
to use clientConfig.service instead.

如果您的集群配置通过停用控制平面虚拟机实例的外部 IP 地址来阻止 Kubernetes API 服务器的直接出站流量,则会出现此错误。GKE 使用 ValidatingAdmissionPolicy 来防止创建或更新使用 clientConfig.url 字段的网络钩子配置。

如需验证此错误的原因,请描述您的集群配置:

gcloud container clusters describe CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --format='value(controlPlaneEgress)'

替换以下内容:

  • CLUSTER_NAME:您的集群的名称。
  • CONTROL_PLANE_LOCATION:集群的区域或可用区,例如 us-central1us-central1-a

如果 API 服务器的出站流量处于停用状态,则输出为 NONE

如需解决此错误,请更新您的 Webhook 配置,以使用 clientConfig.service 字段。借助此字段,API 服务器可以将准入请求发送到集群中的服务,而不是将流量发送到 IP 地址或网址。如需详细了解如何配置网络钩子和服务,请参阅外部网络钩子配置

如果您删除 ValidatingAdmissionPolicy,您的 webhook 创建或更新请求将成功,但对 webhook 服务器的准入请求将失败。

外部准入 webhook 请求失败

当您尝试部署会触发集群 VPC 网络外部的准入网络钩子服务器的 Kubernetes 资源时,会发生以下错误:

Error from server (InternalError): error when creating "STDIN": Internal error occurred: failed calling webhook WEBHOOK_NAME": failed to call webhook: Post "WEBHOOK_URL": proxyconnect tcp: dial tcp: lookup master-internet-access-unavailable.localhost on 169.254.169.254:53: no such host

当满足以下所有条件时,就会出现此错误:

  • Webhook 配置使用 IP 地址或网址来联系外部 webhook 服务器。
  • 集群配置通过停用控制平面虚拟机实例的外部 IP 地址来阻止来自 Kubernetes API 服务器的直接出站流量。

如需验证此错误的原因,请描述您的集群配置:

gcloud container clusters describe CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --format='value(controlPlaneEgress)'

替换以下内容:

  • CLUSTER_NAME:您的集群的名称。
  • CONTROL_PLANE_LOCATION:集群的区域或可用区,例如 us-central1us-central1-a

如果 API 服务器的出站流量处于停用状态,则输出为 NONE

如需解决此错误,请按以下步骤操作:

  1. 确定集群中是否有使用 clientConfig.url 字段的 ValidatingWebhookConfigurations 或 MutatingWebhookConfigurations。
  2. 更新您的 Webhook 配置以使用 clientConfig.service 字段。 借助此字段,API 服务器可以向集群中的服务发送准入请求,而不是向 IP 地址或网址发送流量。如需详细了解如何配置网络钩子和服务,请参阅外部网络钩子配置

触发准入网络钩子超时的 API 请求

表现

如果准入 webhook 配置为使用具有 443 以外的 targetPort 的服务,则触发该准入 webhook 的 API 请求会超时,导致请求失败:

Error from server (Timeout): request did not complete within requested timeout 30s
潜在原因

默认情况下,除端口 443 (HTTPS) 和 10250 (kubelet) 外,防火墙不允许与节点的 TCP 连接。如果没有允许流量的自定义防火墙规则,尝试在端口 443 以外的端口上与 pod 通信的准入网络钩子会失败。

解决方法

为特定用例添加防火墙规则

由于健康检查失败,因此无法创建集群

表现

创建具有专用节点池的 Standard 集群后,它会卡在健康检查步骤,并报告类似于以下内容之一的错误:

All cluster resources were brought up, but only 0 of 2 have registered.
All cluster resources were brought up, but: 3 nodes out of 4 are unhealthy
潜在原因

以下配置可能会导致此错误:

  • 集群节点无法从 Cloud Storage API (storage.googleapis.com) 下载所需的二进制文件。
  • 限制出站流量的防火墙规则。
  • 共享 VPC IAM 权限不正确。
  • 专用 Google 访问通道要求您为 *.gcr.io 配置 DNS。
解决方法

请使用以下任一解决方案:

kubelet 无法创建 pod 沙盒

表现

创建具有专用节点的集群后,系统会报告类似于以下内容之一的错误:

Warning  FailedCreatePodSandBox  12s (x9 over 4m)      kubelet  Failed to create pod sandbox: rpc error: code = Unknown desc = Error response from daemon: Get https://registry.k8s.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
潜在原因

calico-nodenetd Pod 无法访问 *.gcr.io

解决方法

确保您已完成所需的 Container Registry 或 Artifact Registry 设置

已创建专用节点,但未加入集群

对于仅使用具有专用 IP 地址的节点的集群,通常在 VPC 上使用自定义路由和第三方网络设备时,默认路由 (0.0.0.0/0) 会重定向到设备,而不是默认互联网网关。除了控制平面连接外,您还需要确保可以到达以下目的地:

  • *.googleapis.com
  • *.gcr.io
  • gcr.io

为所有三个网域配置专用 Google 访问通道。利用此最佳做法,新节点可以启动并加入集群,同时使互联网出站流量受到限制。

GKE 集群上的工作负载无法访问互联网

在具有专用 IP 地址的节点中运行的 Pod 无法访问互联网。例如,从 Pod exec shell 运行 apt update 命令后,它会报告类似于以下内容的错误:

0% [Connecting to deb.debian.org (199.232.98.132)] [Connecting to security.debian.org (151.101.130.132)]

如果未在 Cloud NAT 网关上配置集群中用于 Pod 的子网次要 IP 地址范围,则 Pod 无法连接到互联网,因为它们没有为 Cloud NAT 网关配置外部 IP 地址。

请务必将 Cloud NAT 网关配置为至少对集群使用的子网应用以下子网 IP 地址范围:

  • 子网主要 IP 地址范围(由节点使用)
  • 集群中用于 Pod 的子网次要 IP 地址范围
  • 集群中用于 Service 的子网次要 IP 地址范围

如需了解详情,请参阅如何添加用于 Pod 的次要子网 IP 范围

无法为公共集群停用直接 IP 访问

表现

停用 IP 地址端点后,您会看到类似于以下内容的错误消息:

Direct IP access can't be disabled for public clusters
潜在原因

您的集群使用的是旧式网络

解决方法

将集群迁移到 Private Service Connect。如需详细了解迁移状态,请 与支持团队联系

无法为正在进行 PSC 迁移的集群停用直接 IP 访问

表现

停用 IP 地址端点后,您会看到类似于以下内容的错误消息:

Direct IP access can't be disabled for public clusters
潜在原因

您的集群使用的是旧式网络

解决方法

请使用以下任一解决方案:

  • 手动以其他版本重新创建所有节点池。
  • 等到 GKE 在维护事件期间自动升级节点池完成。

无法启用控制平面内部端点

表现

尝试启用集群控制平面的内部端点时,您看到类似于以下内容的错误消息:

private_endpoint_enforcement_enabled can't be enabled when envoy is disabled
private_endpoint_enforcement_enabled is unsupported. Please upgrade to the minimum support version
潜在原因

您的集群需要进行 IP 地址轮替或版本更新。

解决方法

请使用以下任一解决方案:

集群创建在定义组织政策时失败

表现

尝试创建集群时,您看到类似于以下内容的错误消息:

compute.disablePrivateServiceConnectCreationForConsumers violated for projects
潜在原因

集群端点或后端被使用方组织政策阻止。

解决方法

完成使用方端组织政策中的步骤,以允许实例创建具有 compute.restrictPrivateServiceConnectProducer 限制条件的端点。

Private Service Connect 端点可能会在集群删除期间泄露

表现

创建集群后,您可能会看到以下某种表现:

  • 基于 Private Service Connect 的集群中,您无法在 Private Service Connect 下看到已连接的端点。

  • 您无法删除使用 Private Service Connect 的集群中为内部端点分配的子网或 VPC 网络。系统会显示类似于以下内容的错误消息:

    projects/<PROJECT_ID>/regions/<REGION>/subnetworks/<SUBNET_NAME> is already being used by projects/<PROJECT_ID>/regions/<REGION>/addresses/gk3-<ID>
    
潜在原因

在使用 Private Service Connect 的 GKE 集群上,GKE 会使用转发规则部署 Private Service Connect 端点,该转发规则会分配一个内部 IP 地址,以便在控制平面的网络中访问集群的控制平面。为了使用 Private Service Connect 保护控制平面与节点之间的通信,GKE 会使该端点不可见,您无法在Google Cloud 控制台或 gcloud CLI 中看到该端点。

解决方法

为防止在集群删除之前泄露 Private Service Connect 端点,请完成以下步骤:

  1. Kubernetes Engine Service Agent role 分配给 GKE 服务账号。
  2. 确保 GKE 服务账号未明确拒绝 compute.forwardingRules.*compute.addresses.* 权限。

如果您看到 Private Service Connect 端点泄露,请 与支持团队联系

无法解析集群已获授权的网络

表现

您无法创建 1.29 版或更高版本的集群。系统会显示类似于以下内容的错误消息:

Unable to parse cluster.master_ipv4_cidr "" into a valid IP address and mask
潜在原因

您的 Google Cloud 项目使用基于专用 IP 的 webhook。因此,您无法创建使用 Private Service Connect 的集群。您的集群使用 VPC 网络对等互连,它会解析 master-ipv4-cidr 标志。

解决方法

请使用以下任一解决方案:

  • 继续创建 VPC 网络对等互连集群,并添加 master-ipv4-cidr 以定义有效的 CIDR。此解决方案存在以下限制:

    • master-ipv4-cidr 标志已在 Google Cloud 控制台中弃用。如需更新此标志,您只能使用 Google Cloud CLI 或 Terraform。
    • VPC 网络对等互连已在 GKE 1.29 版或更高版本中弃用。
  • 按照Private Service Connect 限制中的步骤迁移基于专用 IP 的 Webhook。然后,与支持团队联系,以选择使用 Private Service Connect 的集群。

无法在具有公共节点的集群中定义内部 IP 地址范围

表现

您无法使用 --master-ipv4-cidr 标志定义内部 IP 地址范围。系统会显示类似于以下内容的错误消息:

ERROR: (gcloud.container.clusters.create) Cannot specify --master-ipv4-cidr
  without --enable-private-nodes
潜在原因

您正在没有启用 enable-private-nodes 标志的集群中使用 master-ipv4-cidr 标志为控制平面定义内部 IP 地址范围。如需创建定义了 master-ipv4-cidr 的集群,您必须使用 enable-private-nodes 标志将集群配置为预配具有内部 IP 地址的节点(专用节点)。

解决方法

请使用以下任一解决方案:

  • 使用以下命令创建集群:

    gcloud container clusters create-auto CLUSTER_NAME \
        --enable-private-nodes \
        --master-ipv4-cidr CP_IP_RANGE
    

    替换以下内容:

    • CLUSTER_NAME:您的集群的名称。
    • CLUSTER_NAME:控制平面的内部 IP 地址范围。
  • 更新集群,以预配仅具有 IP 地址的节点。如需了解详情,请参阅配置集群

无法在 Autopilot 集群上调度公共工作负载

表现
在 Autopilot 集群中,如果您的集群仅使用专用节点,则您无法使用 cloud.google.com/private-node=false nodeSelector 在公共 Pod 中调度工作负载。
潜在原因
在 Pod 的 nodeSelector 中将 private-node 标志设置为 false 的配置仅适用于 1.30.3 版或更高版本的集群。
解决方法
将集群升级到 1.30 版或更高版本。

对基于 DNS 的端点的访问权限被停用

表现

尝试针对集群运行 kubectl 命令时,系统返回类似于以下内容的错误:

couldn't get current server API group list:
control_plane_endpoints_config.dns_endpoint_config.allow_external_traffic is
disabled
潜在原因

集群上基于 DNS 的访问权限已被停用。

解决方法

启用使用控制平面基于 DNS 的端点访问控制平面的功能。如需了解详情,请参阅修改控制平面访问权限

节点在扩缩期间无法分配 IP 地址

表现

尝试将子网的主要 IP 地址范围扩展到已获授权的网络列表时,系统会返回类似于以下内容的错误:

 authorized networks fields cannot be mutated if direct IP access is disabled
潜在原因

您已停用集群基于 IP 的端点

解决方法

使用 enable-ip-access 标志停用和启用集群基于 IP 的端点

CIDR 地址块太多

在尝试创建或更新具有超过 50 个 CIDR 地址块的集群时,gcloud 将返回以下错误:

ERROR: (gcloud.container.clusters.update) argument --master-authorized-networks: too many args

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

无法连接到服务器

由于 CIDR 地址块配置错误,kubectl 命令超时:

Unable to connect to the server: dial tcp MASTER_IP: getsockopt: connection timed out

创建或更新集群时,请确保指定了正确的 CIDR 块

节点可以在网络隔离的情况下访问公共容器映像

表现

您可能会发现,在配置为网络隔离的 GKE 集群中,拉取 redis 等常见公共映像可以成功,但拉取不太常见或专用映像会失败。

这是 GKE 的默认配置所致,属于预期行为,并不表示 GKE 已绕过您的网络隔离。

潜在原因

此行为是由于两个功能协同工作而导致的:

  • 专用 Google 访问通道:此功能允许具有内部 IP 地址的节点连接到 Google Cloud API 和服务,而无需公共 IP 地址。专用 Google 访问通道会在集群的子网(位于集群中节点所用的 VPC 内)上激活。使用 --enable-private-nodes 标志创建或更新集群或节点池时,GKE 会自动在此子网上启用专用 Google 访问通道。唯一的例外情况是,如果您使用的是共享 VPC,则必须手动启用专用 Google 访问通道。
  • Google 的映像镜像 (mirror.gcr.io):默认情况下,GKE 会将其节点配置为首先尝试从 mirror.gcr.io(一个由 Google 管理的 Artifact Registry,用于缓存经常请求的公共容器映像)拉取映像。

当您尝试拉取 redis 等映像时,节点会使用专用 Google 访问通道中的专用路径连接到 mirror.gcr.io。由于 redis 是非常常见的映像,因此它存在于缓存中,并且拉取成功。不过,如果您请求的映像不在该公共缓存中,拉取会失败,因为您的隔离节点无法通过其他方式访问其原始来源。

解决方法

如果您需要的映像在 mirror.gcr.io 缓存中不可用,请将其托管在您自己的私有 Artifact Registry 代码库中。网络隔离的节点可以使用专用 Google 访问通道访问此代码库。

后续步骤