使用网络政策控制 Pod 和 Service 之间的通信


本页面介绍了如何使用 GKE 的网络政策实施功能来控制集群的 Pod 和 Service 之间的通信。

您还可以使用完全限定的域名 (FQDN) 网络政策控制 Pod 流向集群外部的任何端点或 Service 的出站流量。如需了解详情,请参阅使用 FQDN 控制 Pod 和服务之间的通信

GKE 网络政策实施功能的简介

借助网络政策实施功能,您可以在集群中创建 Kubernetes 网络政策。网络政策会创建 Pod 级层防火墙规则,以确定哪些 Pod 和 Service 可以在您的集群内相互访问。

定义网络政策可帮助您在集群服务于多级应用时启用深度防御等功能。例如,您可以创建网络政策,以确保应用中受侵的前端服务无法直接与低了几个级层的结算或记账服务进行通信。

网络政策还可以使您的应用更容易同时托管来自多个用户的数据。例如,您可以通过定义每个命名空间一个租户的模型来提供安全的多租户服务。在此类模型中,网络政策规则可确保给定命名空间中的 Pod 和服务无法访问其他命名空间中的其他 Pod 或服务。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

要求和限制

以下要求和限制适用于 Autopilot 集群和 Standard 集群: 以下要求和限制仅适用于 Standard 集群:

  • 如果您将网络政策与适用于 GKE 的工作负载身份联合搭配使用,则必须允许出站流量流向元数据服务器。
  • 启用网络政策实施功能会使 kube-system 进程的内存占用量增加大约 128 MB,并且需要大约 300 millicore 的 CPU。这意味着,如果您为现有集群启用网络政策,则可能需要增加集群的大小以继续运行计划的工作负载。
  • 启用网络政策强制执行功能需要重新创建节点。如果您的集群具备有效的维护窗口,则在下一个维护窗口之前不会自动重新创建节点。如果您愿意,可以随时手动升级集群
  • 运行网络政策实施功能的建议集群大小下限是三个 e2-medium 实例
  • 由于资源要求太高,因此节点为 f1-microg1-small 实例的集群不支持网络政策。

如需详细了解节点机器类型和可分配资源,请参阅标准集群架构 - 节点

启用网络政策实施功能

默认情况下,Autopilot 集群会启用网络政策实施功能,因此您可以跳至创建网络政策

您可以使用 gcloud CLI、Google Cloud 控制台或 GKE API 在 Standard 中启用网络政策实施功能。

网络政策实施功能内置于 GKE Dataplane V2 中。您不需要在使用 GKE Dataplane V2 的集群中启用网络政策实施功能。

gcloud

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. 如需在创建新集群时启用网络政策强制执行功能,请运行以下命令:

    gcloud container clusters create CLUSTER_NAME --enable-network-policy
    

    CLUSTER_NAME 替换为新集群的名称。

    如需为现有集群启用网络政策强制执行功能,请执行以下任务:

    1. 运行以下命令以启用该插件:

      gcloud container clusters update CLUSTER_NAME --update-addons=NetworkPolicy=ENABLED
      

      CLUSTER_NAME 替换为您的集群的名称。

    2. 运行以下命令以在您的集群上启用网络政策强制执行功能,之后系统会为集群重新创建启用了网络政策强制执行功能的节点池:

      gcloud container clusters update CLUSTER_NAME --enable-network-policy
      

控制台

如需在创建新集群时启用网络政策强制执行功能,请执行以下操作:

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

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. 创建集群对话框中,点击 GKE Standard 对应的配置

  4. 根据您的选择配置集群。

  5. 在导航窗格的集群下,点击网络

  6. 选中启用网络政策复选框。

  7. 点击创建

如需为现有集群启用网络政策强制执行功能,请执行以下操作:

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

    转到 Google Kubernetes Engine

  2. 在集群列表中,点击您要修改的集群的名称。

  3. 网络下的网络政策字段中,点击 修改网络政策

  4. 选中启用主节点的网络政策复选框,然后点击保存更改

  5. 等待更改应用,然后再次点击 修改网络政策

  6. 选中启用节点的网络政策复选框。

  7. 点击保存更改

API

如需启用网络政策强制执行功能,请执行以下操作:

  1. 在您提供给 projects.zones.clusters.createprojects.zones.clusters.updatecluster 对象中指定 networkPolicy 对象。

  2. networkPolicy 对象需要一个用于指定要使用的网络政策提供者的枚举值,以及一个指定是否启用网络政策的布尔值。如果启用网络政策但未设置提供者,则 createupdate 命令将返回错误。

在 Standard 集群中停用网络政策实施功能

您可以使用 gcloud CLI、Google Cloud 控制台或 GKE API 停用网络政策实施功能。您无法在 Autopilot 集群或使用 GKE Dataplane V2 的集群中停用网络政策实施功能。

gcloud

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. 如需停用网络政策强制执行功能,请执行以下任务:

    1. 在集群上停用网络政策强制执行功能:
    gcloud container clusters update CLUSTER_NAME --no-enable-network-policy
    

    CLUSTER_NAME 替换为您的集群的名称。

    运行此命令后,GKE 会为集群重新创建停用了网络政策强制执行功能的节点池。

  3. 验证是否已重新创建所有节点:

    kubectl get nodes -l projectcalico.org/ds-ready=true
    

    如果操作成功,则输出类似于以下内容:

    No resources found
    

    但如果输出类似于以下内容,则必须等待 GKE 完成节点池更新:

    NAME                                             STATUS                     ROLES    AGE     VERSION
    gke-calico-cluster2-default-pool-bd997d68-pgqn   Ready,SchedulingDisabled   <none>   15m     v1.22.10-gke.600
    gke-calico-cluster2-np2-c4331149-2mmz            Ready                      <none>   6m58s   v1.22.10-gke.600
    

    停用网络政策强制执行功能后,如果您的集群配置了维护期或排除项,GKE 可能不会立即更新节点。如需了解详情,请参阅集群更新缓慢

  4. 重新创建所有节点后,停用插件:

    gcloud container clusters update CLUSTER_NAME --update-addons=NetworkPolicy=DISABLED
    

控制台

如需为现有集群停用网络政策强制执行功能,请执行以下操作:

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

    转到 Google Kubernetes Engine

  2. 在集群列表中,点击您要修改的集群的名称。

  3. 网络下的网络政策字段中,点击 修改网络政策

  4. 清除启用节点的网络政策复选框,然后点击保存更改

  5. 等待更改应用,然后再次点击 修改网络政策

  6. 清除启用主节点的网络政策复选框。

  7. 点击保存更改

API

如需为现有集群停用网络政策强制执行功能,请执行以下操作:

  1. 通过 setNetworkPolicy API 将集群更新为使用 networkPolicy.enabled: false

  2. 验证已使用 gcloud CLI 重新创建了所有节点:

    kubectl get nodes -l projectcalico.org/ds-ready=true
    

    如果操作成功,则输出类似于以下内容:

    No resources found
    

    但如果输出类似于以下内容,则必须等待 GKE 完成节点池更新:

    NAME                                             STATUS                     ROLES    AGE     VERSION
    gke-calico-cluster2-default-pool-bd997d68-pgqn   Ready,SchedulingDisabled   <none>   15m     v1.22.10-gke.600
    gke-calico-cluster2-np2-c4331149-2mmz            Ready                      <none>   6m58s   v1.22.10-gke.600
    

    停用网络政策强制执行功能后,如果您的集群配置了维护期或排除项,GKE 可能不会立即更新节点。如需了解详情,请参阅集群更新缓慢

  3. 通过 updateCluster API 更新集群以使用 update.desiredAddonsConfig.NetworkPolicyConfig.disabled: true

创建网络政策

您可以使用 Kubernetes Network Policy API 创建网络政策。

如需详细了解如何创建网络政策,请参阅 Kubernetes 文档中的以下主题:

网络政策和适用于 GKE 的工作负载身份联合

如果您将网络政策与适用于 GKE 的工作负载身份联合搭配使用,您必须允许流向以下 IP 地址的出站流量,以便 Pod 能够与 GKE 元数据服务器通信。

  • 对于运行 GKE 1.21.0-gke.1000 及更高版本的集群,允许出站流量经端口 988 流向 169.254.169.252/32
  • 对于运行低于 1.21.0-gke.1000 的 GKE 版本的集群,允许出站流量经端口 988 流向 127.0.0.1/32
  • 对于运行 GKE Dataplane V2 的集群,允许出站流量经端口 80 流向 169.254.169.254/32

如果您不允许出站流量流向这些 IP 地址和端口,则在自动升级期间可能会遇到中断。

从 Calico 迁移到 GKE Dataplane V2

如果您将网络政策从 Calico 迁移到 GKE Dataplane V2,请考虑以下限制:

  • 您不能在 NetworkPolicy 清单的 ipBlock.cidr 字段中使用 Pod 或 Service IP 地址。您必须使用标签来引用工作负载。例如,以下配置无效:

    - ipBlock:
        cidr: 10.8.0.6/32
    
  • 不得在 NetworkPolicy 清单中指定空的 ports.port 字段。如果指定了协议,则还必须指定端口。例如,以下配置无效:

    ingress:
    - ports:
      - protocol: TCP
    

使用应用负载均衡器

将 Ingress 应用于 Service 以构建应用负载均衡器时,您必须配置应用于该 Service 背后的 Pod 的网络政策,以允许适当的应用负载均衡器健康检查 IP 范围。如果您使用的是内部应用负载均衡器,则还必须配置网络政策以允许代理专用子网

如果您没有对网络端点组使用容器原生负载均衡,则 Service 的节点端口可能会将连接转发到其他节点上的 Pod,除非通过在 Service 定义中将 externalTrafficPolicy 设置为 Local 来阻止它们这样做。如果 externalTrafficPolicy 未设置为 Local,则网络政策还必须允许从集群中的其他节点 IP 进行连接。

在 ipBlock 规则中包含 Pod IP 地址范围

如需控制特定 Pod 的流量,请始终使用 NetworkPolicy 入站流量或出站流量规则中的 namespaceSelectorpodSelector 字段按命名空间或 Pod 标签选择 Pod。请勿使用 ipBlock.cidr 字段有意选择 Pod IP 地址范围(此范围本质上是临时的)。Kubernetes 项目包含 Pod IP 地址范围时,不会明确定义 ipBlock.cidr 字段的行为。在此字段中指定宽泛的 CIDR 范围(例如 0.0.0.0/0 [包括 Pod IP 地址范围])在 NetworkPolicy 的不同实现中可能会产生意外结果。

以下部分介绍了 GKE 中不同的 NetworkPolicy 实现如何评估您在 ipBlock.cidr 字段中指定的 IP 地址范围,以及这可能对本身包含在广泛的 CIDR 范围的 Pod IP 地址范围的影响。了解各实现之间的不同行为有助于您在迁移到其他实现时为结果做好准备。

GKE Dataplane V2 中的 ipBlock 行为

使用 NetworkPolicy 的 GKE Dataplane V2 实现时,ipBlock 规则绝不会涵盖 Pod 流量。因此,即使您定义了宽泛的规则(例如 cidr: '0.0.0.0/0'),它也不会包含 Pod 流量。这非常有用,例如,您可以允许命名空间中的 Pod 接收来自互联网的流量,但不允许来自 Pod 的流量。如需同时添加 Pod 流量,请在 NetworkPolicy 的入站流量或出站流量规则定义中使用其他 Pod 或命名空间选择器明确选择 Pod。

Calico 的 ipBlock 行为

对于 NetworkPolicy 的 Calico 实现,ipBlock 规则确实涵盖 Pod 流量。使用此实现时,如需配置广泛的 CIDR 范围而不允许 Pod 流量,请明确排除集群的 Pod CIDR 范围,如以下示例所示:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-non-pod-traffic
spec:
  ingress:
  - from:
    - ipBlock:
      cidr: '0.0.0.0/0'
      except: ['POD_IP_RANGE']

在此示例中,POD_IP_RANGE 是您的集群的 Pod IPv4 地址范围,例如 10.95.0.0/17。如果您有多个 IP 地址范围,可单独将其包含在数组中,例如 ['10.95.0.0/17', '10.108.128.0/17']

问题排查

Pod 无法与使用 Private Service Connect 的集群上的控制平面通信

如果出站流量网络政策限制使用 Private Service Connect 的 GKE 集群上的 Pod 到控制平面的内部 IP 地址的出站流量,则 Pod 可能会遇到与控制平面的通信问题。

为了缓解这一问题:

  1. 查看您的集群是否使用 Private Service Connect。如需了解详情,请参阅使用 Private Service Connect 的公共集群。在使用 Private Service Connect 的集群上,每个控制平面都分配有集群节点子网中的内部 IP 地址。

  2. 配置集群的出站流量政策以允许发送到控制平面的内部 IP 地址的流量。

    如需查找控制平面的内部 IP 地址,请执行以下操作:

    gcloud

    如需查找 privateEndpoint,请运行以下命令:

    gcloud container clusters describe CLUSTER_NAME
    

    CLUSTER_NAME 替换为您的集群的名称。

    此命令会检索指定集群的 privateEndpoint

    控制台

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

      转到 Google Kubernetes Engine

    2. 在导航窗格的集群下,点击要查找内部 IP 地址的集群。

    3. 集群基本信息下,找到列出内部 IP 地址的 Internal endpoint

    在找到 privateEndpointInternal endpoint 后,请配置集群的出站流量政策以允许发送到控制平面的内部 IP 地址的流量。如需了解详情,请参阅创建网络政策

集群更新缓慢

在现有集群上启用或停用网络政策强制执行功能时,如果集群配置了维护期或排除项,则 GKE 可能不会立即更新节点。

您可以通过将 --cluster-version 标志设置为控制平面运行的同一 GKE 版本来手动升级节点池。您必须使用 Google Cloud CLI 执行此操作。如需了解详情,请参阅维护窗口的注意事项

取消安排手动部署的 Pod

在现有集群的控制平面上启用网络政策强制执行功能后,GKE 会取消安排任何手动部署的 ip-masquerade-agent 或 calico 节点 Pod。

在集群节点上启用网络政策强制执行功能并重新创建节点之前,GKE 不会重新安排这些 Pod。

如果您配置了维护时段或排除项,这可能会导致中断时间变长。

为了最大限度地减少中断的时长,您可以手动为集群节点分配以下标签:

  • node.kubernetes.io/masq-agent-ds-ready=true
  • projectcalico.org/ds-ready=true

网络政策未生效

如果 NetworkPolicy 未生效,则可以按照以下步骤进行问题排查:

  1. 确认已启用网络政策实施功能。使用的命令取决于您的集群是否已启用 GKE Dataplane V2。

    如果您的集群已启用 GKE Dataplane V2,请运行以下命令:

    kubectl -n kube-system get pods -l k8s-app=cilium
    

    如果输出为空,则表明未启用网络政策实施功能。

    如果您的集群未启用 GKE Dataplane V2,请运行以下命令:

    kubectl get nodes -l projectcalico.org/ds-ready=true
    

    如果输出为空,则表明未启用网络政策实施功能。

  2. 检查 Pod 标签:

    kubectl describe pod POD_NAME
    

    POD_NAME 替换为 Pod 的名称。

    输出内容类似如下:

    Labels:        app=store
                   pod-template-hash=64d9d4f554
                   version=v1
    
  3. 确认政策上的标签与 Pod 上的标签匹配:

    kubectl describe networkpolicy
    

    输出内容类似如下:

    PodSelector: app=store
    

    在此输出中,app=store 标签与上一步中的 app=store 标签匹配。

  4. 检查是否有任何网络政策选择您的工作负载:

    kubectl get networkpolicy
    

    如果输出为空,则表明没有在命名空间中创建 NetworkPolicy,并且没有任何网络政策选择您的工作负载。如果输出不为空,请检查政策是否选择了您的工作负载:

    kubectl describe networkpolicy
    

    输出内容类似如下:

    ...
    PodSelector:     app=nginx
    Allowing ingress traffic:
       To Port: <any> (traffic allowed to all ports)
       From:
          PodSelector: app=store
    Not affecting egress traffic
    Policy Types: Ingress
    

已知问题

使用 Calico 终止 StatefulSet Pod

启用了 Calico 网络政策的 GKE 集群可能会遇到以下问题:删除 StatefulSet pod 时,该 pod 会丢弃现有连接。在 pod 进入 Terminating 状态后,将不会再遵循 pod 规范中的 terminationGracePeriodSeconds 配置,并且会导致当前与 StatefulSet pod 连接的其他应用中断。如需详细了解此问题,请参阅 Calico 问题 #4710

此问题会影响以下 GKE 版本:

  • 1.18
  • 1.19 至 1.19.16-gke.99
  • 1.20 至 1.20.11-gke.1299
  • 1.21 至 1.21.4-gke.1499

为了缓解这一问题,请将 GKE 控制平面升级到以下版本之一:

  • 1.19.16-gke.100 或更高版本
  • 1.20.11-gke.1300 或更高版本
  • 1.21.4-gke.1500 或更高版本

Pod 卡滞在 containerCreating 状态

在某些情况下,启用了 Calico 网络政策的 GKE 集群可能会遇到 Pod 卡滞在 containerCreating 状态的问题。

在 Pod 事件标签页下,您会看到类似于以下内容的消息:

plugin type="calico" failed (add): ipAddrs is not compatible with
configured IPAM: host-local

为了缓解这一问题,请在 GKE 集群中使用 Calico 的 host-local ipam 而不是 calico-ipam。

后续步骤