网络概览


本页面将介绍 Google Kubernetes Engine (GKE) 网络的几个主要方面。这些信息适合刚刚开始使用 Kubernetes 的人员,以及经验丰富的集群运营商或应用开发者;他们需要具备更多的 Kubernetes 网络知识,以便更好地设计应用或配置 Kubernetes 工作负载。

本页面适用于为组织设计和架构网络的云架构师和网络专家。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务

利用 Kubernetes,您能以声明方式来定义应用的部署方式、应用与应用之间以及应用与 Kubernetes 控制层面之间的通信方式,还可以定义客户端访问应用的方式。本页面还介绍了 GKE 如何配置与网络相关的 Google Cloud 服务。

在使用 Kubernetes 编排应用时,您必须改变对应用及其主机的网络设计的构思方式。使用 Kubernetes 时,您需要考虑的是 Pod、Service 和外部客户端的通信方式,而不是主机或虚拟机 (VM) 的连接方式。

Kubernetes 的高级软件定义网络 (SDN) 支持在同一区域级集群中的不同地区之间路由和转发 Pod、Service、节点的数据包。Kubernetes 和 Google Cloud 还会在每个节点上动态配置 IP 过滤规则、路由表和防火墙规则,具体取决于 Kubernetes 部署的声明模型和 Google Cloud 上的集群配置。

前提条件

在阅读本页之前,最好确保您熟悉 Linux 网络管理概念和实用程序,例如 iptables 规则和路由。

此外,请确保您熟悉以下主题的基本术语:

Kubernetes 网络模型在很大程度上依赖于 IP 地址。服务、Pod、容器和节点使用 IP 地址和端口进行通信。Kubernetes 提供不同类型的负载均衡,用于将流量定向到正确的 Pod。本主题的后面部分将更详细地介绍所有这些机制。在阅读本页中的内容时,请牢记以下术语:

  • ClusterIP:分配给服务的 IP 地址。在其他文档中,这可能被称为“集群 IP”。此地址会在 Service 的生命周期内保持不变,如 Service 中所述。
  • Pod IP 地址:分配给给定 Pod 的 IP 地址。这是临时地址,具体请参阅 Pod
  • 节点 IP 地址:分配给给定节点的 IP 地址。

集群的网络要求

公共集群和专用集群都需要建立到 *.googleapis.com*.gcr.io 和控制平面 IP 地址的连接。隐式允许出站规则以及由 GKE 自动创建的防火墙规则可满足此要求。

对于公共集群,如果您添加了拒绝具有更高优先级的出站流量的防火墙规则,则必须创建防火墙规则以允许 *.googleapis.com*.gcr.io 和控制平面 IP 地址。

如需详细了解专用集群要求,请参阅要求、限制和局限

集群内部网络

本部分介绍了 Kubernetes 集群中的网络设置,它与 IP 分配PodServiceDNS控制平面相关。

IP 分配

Kubernetes 使用各种 IP 范围为节点、Pod 和服务分配 IP 地址。

  • 系统会从集群的 Virtual Private Cloud (VPC) 网络为每个节点分配一个 IP 地址。此节点 IP 地址用于提供从控制组件(如 kube-proxykubelet)到 Kubernetes API 服务器的连接。此 IP 地址用于提供节点与集群其余组件的连接。
  • 每个节点都有一个 IP 地址池(默认为 /24 CIDR 块),供 GKE 分配在该节点上运行的 Pod。您可以选择在创建集群时指定 IP 地址范围。 借助灵活的 Pod CIDR 范围功能,您可以缩小节点池中节点的 Pod IP 地址范围。
  • 每个 Pod 都有从其节点的 Pod CIDR 范围分配的单个 IP 地址。此 IP 地址由 Pod 内运行的所有容器共享,并将它们连接到集群中运行的其他 Pod。
  • 系统会从集群的 VPC 网络为每项服务分配一个 IP 地址(称为 ClusterIP)。您可以选择在创建集群时自定义 VPC 网络。
  • 每个控制平面都有一个公共或内部 IP 地址,具体取决于集群类型、版本和创建日期。如需了解详情,请参阅控制层面说明。

GKE 网络模型不允许在整个网络中重复使用 IP 地址。迁移到 GKE 时,您必须规划 IP 地址分配,以减少 GKE 中的内部 IP 地址用量

MTU

为 Pod 接口选择的 MTU 取决于集群节点使用的容器网络接口 (CNI) 和底层 VPC MTU 设置。如需了解详情,请参阅 Pod

Pod 接口 MTU 值为 1460 或从节点的主要接口继承。

CNI MTU GKE Standard
kubenet 1460 默认
kubenet
(GKE 1.26.1 版及更高版本)
继承 默认
Calico 1460

使用 --enable-network-policy 启用。

如需了解详情,请参阅使用网络政策控制 Pod 与服务之间的通信

netd 继承 通过以下任一方式启用:
GKE Dataplane V2 继承

使用 --enable-dataplane-v2 启用。

如需了解详细信息,请参阅使用 GKE Dataplane V2

如需了解详情,请参阅 VPC 原生集群

支持的网络插件

  • 如需使用网络插件,您必须自行安装。GKE 提供以下原生支持的网络插件:
    • Calico(在 Dataplane V1 中)
    • Cilium(在 Dataplane V2 中)
    • Istio-CNI(在 GKE Enterprise 的托管式数据平面控制器中)

pod

在 Kubernetes 中,Pod 是可在 Kubernetes 集群中部署的最基本单元。Pod 运行一个或多个容器。 节点运行零个或更多 Pod。 集群中的每个节点都是节点池的一部分。

在 GKE 中,这些节点是虚拟机,每个节点都作为 Compute Engine 中的一个实例运行。

Pod 还可以连接到外部存储卷和其他自定义资源。 下图显示了一个运行两个 Pod 的节点,每个 Pod 都连接到两个卷。

图片

当 Kubernetes 安排 Pod 在某节点上运行时,它会在该节点的 Linux 内核中为 Pod 创建网络命名空间。此网络命名空间使用虚拟网络接口将节点的物理网络接口(如 eth0)与 Pod 连接起来,从而使数据包可以进出 Pod。节点的根网络命名空间中的关联虚拟网络接口连接到 Linux 网桥,可让同一节点上的各 Pod 之间进行通信。Pod 还可以使用同一虚拟接口在节点外部发送数据包。

Kubernetes 会从为节点上的 Pod 预留的一系列地址中,为 Pod 的网络命名空间中的虚拟网络接口分配一个 IP 地址(即 Pod IP 地址)。该地址范围是分配给 Pod 所在集群的 IP 地址范围的子集,可在创建集群时进行配置。

Pod 中运行的容器使用 Pod 的网络命名空间。从容器的角度来看,Pod 是具有一个网络接口的物理机器。Pod 中的所有容器都会看到此同一网络接口。 每个容器的 localhost 通过 Pod 连接到节点的物理网络接口(例如 eth0)。

请注意,根据您具体是使用 GKE 的“容器网络接口”(CNI) 还是通过在创建群集时启用网络政策来选择使用 Calico 的实现,该连接会有很大差别。

  • 如果使用 GKE 的 CNI,则虚拟以太网设备 (veth) 对的一端将连接到其命名空间中的 Pod,另一端连接到 Linux 网桥设备cbr01在这种情况下,以下命令会显示连接到 cbr0 的各个 Pod 的 MAC 地址:

    arp -n
    

    在工具箱容器中运行以下命令,显示连接到 cbr0 的各 veth pair 的根命名空间端:

    brctl show cbr0
    
  • 如果启用了网络政策,则 veth pair 的一端连接到 Pod,另一端连接到 eth0。在这种情况下,以下命令会显示连接到不同 veth 设备的各个 Pod 的 MAC 地址:

    arp -n
    

    在工具箱容器中运行以下命令会显示没有名为 cbr0 的 Linux 网桥设备:

    brctl show
    

集群内促进转发的 iptables 规则因场景而异。详细排查连接问题时,必须清楚地意识到这一差别。

默认情况下,每个 Pod 对所有集群节点上运行的其他所有 Pod 都具有未经过滤的访问权限,但您可以限制各 Pod 之间的访问。Kubernetes 会定期删除并重新创建 Pod。如果升级节点池、更改 Pod 的声明性配置、更改容器的映像,或节点不可用,就会发生这种情况。因此,Pod 的 IP 地址属于实现细节,您不应该依赖于这些地址。Kubernetes 使用 Service 提供稳定的 IP 地址。

  1. 仅当存在设置 hostNetwork: false 的 Pod 时,才会创建虚拟网络网桥 cbr0

服务

在 Kubernetes 中,您可以为任何 Kubernetes 资源分配任意键值对(称为标签)。Kubernetes 使用标签来将多个相关的 Pod 组合成一个逻辑单元(称为服务)。服务具有稳定的 IP 地址和端口,并会在一组 Pod 之间提供负载均衡(前提是这些 Pod 的标签与您在创建服务时于标签选择器中定义的所有标签相匹配)。

下图显示了两项独立的 Service,每项 Service 都由多个 Pod 组成。图中的每个 Pod 都带有 app=demo 标签,但这些 Pod 的其他标签有所不同。“frontend” Service 匹配所有带有 app=democomponent=frontend 的 Pod,而“users” Service 匹配所有带有 app=democomponent=users 的 Pod。客户端 Pod 与任一 Service 选择器都不完全匹配,因此它不是任一 Service 的一部分。但是,由于客户端 Pod 在同一集群内运行,因此它可与任一服务进行通信。

图片

Kubernetes 会从集群的可用 Service IP 地址池中为每项新创建的 Service 分配一个稳定可靠的 IP 地址(ClusterIP)。Kubernetes 还会通过添加 DNS 条目为 ClusterIP 地址分配主机名。ClusterIP 地址和主机名在集群内是唯一的,并且在 Service 的整个生命周期内不会更改。只有将 Service 从集群的配置中删除时,Kubernetes 才会释放 ClusterIP 地址和主机名。您可以使用服务的 ClusterIP 或主机名访问正常运行应用的 Pod。

乍一看,服务似乎是应用的单点故障。但是,Kubernetes 会尽可能均匀地将流量分布到在多个节点上运行的一系列 Pod,因此集群可以顺利度过影响一个或多个(但不是所有)节点的服务中断情况。

Kube-Proxy

Kubernetes 使用 kube-proxy 组件(该组件通常作为静态 Pod 在每个节点上运行)管理各个 Pod 和各个 Service 之间的连接。

kube-proxy 不是内嵌代理,而是一个基于出站流量的负载均衡控制器。该组件通过为节点的 iptables 子系统添加目标 NAT (DNAT) 规则以及从中移除这些规则,监控 Kubernetes API 服务器并持续将 ClusterIP 地址映射到运行状况良好的 Pod。当 Pod 中运行的容器将数据包发送到 Service 的 ClusterIP 地址时,节点会随机选择一个 Pod 并将流量路由到该 Pod。

在配置 Service 时,您可以选择定义 porttargetPort 的值来重新映射其监听端口。

  • port 是客户端用来访问应用的位置。
  • targetPort 是应用用来实际监听 Pod 内流量的端口。

kube-proxy 通过在节点上添加 iptables 规则以及从中移除这些规则来管理此端口重新映射过程。

下图演示了从客户端 Pod 到不同节点上的服务器 Pod 的流量流动。客户端通过 172.16.12.100:80 连接到 Service。Kubernetes API 服务器会维护一个运行应用的 Pod 列表。每个节点上的 kube-proxy 进程都使用此列表创建 iptables 规则,将流量定向到适当的 Pod(例如 10.255.255.202:8080)。客户端 Pod 不需要知道集群的拓扑或者个别 Pod 或其中容器的任何详细信息。

图片

kube-proxy 的部署方式取决于集群的 GKE 版本:

  • 对于 GKE 版本 1.16.0 和 1.16.8-gke.13,kube-proxy 会作为 DaemonSet 部署。
  • 对于高于 1.16.8-gke.13 的 GKE 版本,kube-proxy 会作为静态 Pod 部署到节点。

DNS

GKE 提供以下托管集群 DNS 选项来解析服务名称和外部名称:

  • kube-dns:默认情况下,所有 GKE 集群中部署的集群插件。 如需了解详情,请参阅使用 kube-dns

  • Cloud DNS:由云托管集群 DNS 基础架构,用于替换集群中的 kube-dns。如需了解详情,请参阅使用 Cloud DNS for GKE

GKE 还提供了 NodeLocal DNSCache,作为带有 kube-dns 或 Cloud DNS 的可选插件,用于提高集群 DNS 性能。

如需详细了解 GKE 如何提供 DNS,请参阅服务发现和 DNS

控制平面

在 Kubernetes 中,控制平面管理控制平面进程,包括 Kubernetes API 服务器。如何访问控制平面取决于 GKE AutopilotStandard 集群的版本。

使用 Private Service Connect 的集群

满足以下任一条件的专用集群或公共集群使用 Private Service Connect 以私密方式连接节点和控制平面:

  • 2022 年 3 月 15 日或之后创建的 1.23 版新公共集群。
  • 2024 年 1 月 28 日之后,版本为 1.29 的新私有集群。

不符合上述条件的现有公共集群正在迁移到 Private Service Connect。因此,这些集群可能已在使用 Private Service Connect。如需检查您的集群是否使用 Private Service Connect,请运行 gcloud container clusters describe 命令。如果您的公共集群使用 Private Service Connect,则 privateClusterConfig 资源具有以下值:

  • peeringName 字段为空或不存在。
  • privateEndpoint 字段已被分配了一个值。

但是,不符合上述条件的现有专用集群尚未迁移。

您可以创建使用 Private Service Connect 的集群并更改集群隔离。通过定义可访问控制平面的源站,使用授权网络限制对集群控制平面的访问权限。

用于 GKE 集群的 Private Service Connect 资源处于隐藏状态。

对于使用 Private Service Connect 的专用集群,在创建子网时,--master-ipv4-cidr 标志是可选的。如果您使用此标志,GKE 会创建一个新子网,该子网使用您在 --master-ipv4-cidr 中定义的值,并使用新子网为控制平面提供内部 IP 地址。

集群外部网络

本部分介绍来自集群外部的流量如何到达 Kubernetes 集群内运行的应用。在设计集群的应用和工作负载时,此信息非常重要。

您已经了解了 Kubernetes 如何使用 ServicePod 中运行的应用提供稳定的 IP 地址。默认情况下,Pod 不会公开外部 IP 地址,因为每个节点上的所有流量均由 kube-proxy 管理。Pod 及其容器可以自由通信,但集群外部的连接无法访问服务。例如,在上图中,集群外部的客户端无法使用其 ClusterIP 访问前端服务。

GKE 提供了三种不同类型的负载均衡器,用于控制访问并尽可能均匀地将传入流量扩散到整个集群中。您可以将一项 Service 配置为同时使用多种类型的负载均衡器。

  • 外部负载均衡器用于管理来自集群外部和 Google Cloud VPC 网络外部的流量。它们使用与 Google Cloud 网络关联的转发规则来将流量路由到 Kubernetes 节点。
  • 内部负载均衡器用于管理来自同一 VPC 网络的流量。与外部负载均衡器一样,它们使用与 Google Cloud 网络关联的转发规则来将流量路由到 Kubernetes 节点。
  • 应用负载均衡器是专用于处理 HTTP(S) 流量的外部负载均衡器。它们使用 Ingress 资源(而不是转发规则)将流量路由到 Kubernetes 节点。

当流量到达 Kubernetes 节点时,无论负载均衡器为何种类型,这些流量都会按照相同方式进行处理。负载均衡器并不清楚集群中的哪些节点正在为其服务运行 Pod。在这种情况下,它会将流量平衡到集群中的所有节点,即使某些节点并没有运行相关 Pod 也是如此。在区域级集群上,负载将扩散到集群所在区域内所有地区中的所有节点上。当流量路由到某节点时,该节点会将流量路由到一个 Pod;该 Pod 可能在同一节点上运行,也可能在不同节点上运行。该节点使用 iptables 规则(由 kube-proxy 在节点上管理)将流量转发到随机选择的 Pod。

在下图中,外部直通式网络负载均衡器将流量定向到中间节点,然后该流量又被重定向到第一个节点上的 Pod。

图片

当负载均衡器将流量发送到节点时,流量可能会被转发到其他节点上的 Pod。这需要额外的网络跃点。如果要避免额外的跃点,您可以指定流量必须转到最初接收流量的节点上的 Pod。

如需指定流量必须转到同一节点上的 Pod,请在 Service 清单中将 externalTrafficPolicy 设置为 Local

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: demo
    component: users
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

externalTrafficPolicy 设置为 Local 时,负载均衡器仅将流量发送到具有属于 Service 的正常 Pod 的节点。负载均衡器使用健康检查确定哪些节点具有适当的 Pod。

外部负载均衡器

如果您的 Service 需要能够从集群外部或 VPC 网络外部进行访问,您可以将 Service 配置为 LoadBalancer,方法是在定义 Service 时将其 type 字段设置为 Loadbalancer。然后,GKE 会在该 Service 前面预配一个外部直通式网络负载均衡器。外部直通式网络负载均衡器可识别集群中的所有节点,并使用 Service 的外部 IP 地址配置 VPC 网络的防火墙规则,以允许从 VPC 网络外部连接到 Service。您可以为 Service 分配静态外部 IP 地址。

如需了解详情,请参阅使用静态 IP 地址配置域名

如要详细了解防火墙规则,请参阅自动创建的防火墙规则

技术详情

使用外部负载均衡器时,系统最初会使用与 Google Cloud 网络关联的转发规则将到达的流量路由到节点。流量到达节点后,节点会使用其 iptables NAT 表选择 Pod。节点的 iptables 规则由 kube-proxy 管理。

内部负载均衡器

对于需要从同一 VPC 网络内访问集群的流量,您可以将 Service 配置为预配一个内部直通式网络负载均衡器。内部直通式网络负载均衡器会从集群的 VPC 子网中选择一个 IP 地址,而非使用外部 IP 地址。VPC 网络内的应用或服务可以使用此 IP 地址与集群内的 Service 进行通信。

技术详情

内部负载均衡由 Google Cloud 提供。当流量到达给定节点时,该节点会使用其 iptables NAT 表选择 Pod,即使 Pod 位于其他节点上也是如此。节点的 iptables 规则由 kube-proxy 管理。

如需详细了解内部负载均衡器,请参阅使用内部直通式网络负载均衡器

应用负载均衡器

许多应用(如 RESTful Web 服务 API)使用 HTTP(S) 进行通信。您可以使用 Kubernetes Ingress 允许 VPC 网络的外部客户端访问此类应用。

借助 Ingress,您可以将主机名和网址路径映射到集群中的 Service。使用应用负载均衡器时,您必须将 Service 配置为使用 NodePort 和 ClusterIP。当流量通过节点的 IP 地址和 NodePort 到达 Service 时,GKE 会将流量路由到 Service 的运行状况良好的 Pod。您可以指定 NodePort,也可以允许 GKE 随机分配一个未使用的端口。

当您创建 Ingress 资源时,GKE 会在 Google Cloud 项目中预配外部应用负载均衡器。此负载均衡器会通过 NodePort 向节点的 IP 地址发送请求。请求到达节点后,节点会使用其 iptables NAT 表选择 Pod。节点的 iptables 规则由 kube-proxy 管理。

以下 Ingress 定义通过端口 80 将 demo.example.com 流量路由到名为 frontend 的 Service,并通过端口 8080 将 demo-backend.example.com 流量路由到名为 users 的 Service。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo
spec:
  rules:
  - host: demo.example.com
    http:
      paths:
      - backend:
          service:
            name: frontend
            port:
              number: 80
  - host: demo-backend.example.com
    http:
      paths:
      - backend:
          service:
            name: users
            port:
              number: 8080

如需了解详情,请参阅适用于应用负载均衡器的 GKE Ingress

技术详情

当您创建 Ingress 对象时,GKE Ingress 控制器会根据 Ingress 清单及其关联的 Service 清单中的规则配置应用负载均衡器。客户端会向应用负载均衡器发送请求。负载均衡器是一个实际代理;它用于选择节点并将请求转发到该节点的 NodeIP:NodePort 组合。节点使用其 iptables NAT 表选择 Pod。节点的 iptables 规则由 kube-proxy 管理。

限制节点之间的连接

在集群中创建针对节点的入站或出站防火墙规则可能会产生不利影响。例如,将出站拒绝规则应用于集群中的节点可能会破坏 NodePortkubectl exec 等功能。

限制与 Pod 和服务的连接

默认情况下,在同一集群内运行的所有 Pod 都可以自由通信。 但是,您可以根据需要以不同方式限制集群内的连接。

限制 Pod 之间的访问

您可以使用网络政策限制 Pod 之间的访问。通过网络政策定义,您可以根据标签、IP 地址范围和端口号的任意组合来限制 Pod 的入站流量出站流量

默认情况下,系统不配置网络政策,因此允许集群中各个 Pod 之间的所有流量。当您在命名空间中创建第一项网络政策后,系统会拒绝其他所有流量。

创建网络政策后,您必须为集群明确启用该政策。 如需了解详情,请参阅为应用配置网络政策

限制对外部负载均衡器的访问

如果您的 Service 使用外部负载均衡器,则默认情况下,来自任何外部 IP 地址的流量都可以访问您的 Service。通过在配置 Service 时配置 loadBalancerSourceRanges 选项,您可以限制哪些 IP 地址范围可以访问集群内的端点。您可以指定多个范围,并且可以随时更新正在运行的 Service 的配置。在每个节点上运行的 kube-proxy 实例会配置该节点的 iptables 规则,以拒绝与指定的 loadBalancerSourceRanges 不匹配的所有流量。此外,当您创建 LoadBalancer 服务时,GKE 会创建一个相应的 VPC 防火墙规则,以便在网络级别强制执行这些限制。

限制对应用负载均衡器的访问

如果您的服务使用应用负载均衡器,则您可以使用 Google Cloud Armor 安全政策限制哪些外部 IP 地址可以访问您的 Service,以及哪些 IP 地址可以访问安全政策拒绝访问时返回的响应。您可以配置 Cloud Logging 以记录这些交互的相关信息。

如果 Google Cloud Armor 安全政策不够细致,您可以在端点上启用 Identity-Aware Proxy,以针对您的应用实现基于用户的身份验证和授权。如需了解详情,请参阅有关配置 IAP 的详细教程

已知问题

本部分介绍了已知问题。

已启用容器的节点无法连接到 172.17/16 范围

启用了 containerd 的节点虚拟机无法连接到具有 172.17/16 范围内 IP 的主机。如需了解详情,请参阅与 172.17/16 IP 地址范围冲突

已删除的 GKE 集群(使用 Private Service Connect)中的剩余资源

如果您在 2024 年 5 月 7 日之前使用 Private Service Connect 创建和删除了 GKE 集群,并且在删除集群本身之前删除了包含该集群的项目,则可能会泄露关联的 Private Service Connect 资源。这些资源会保持隐藏状态,并且您无法删除关联的子网。如果遇到此问题,请与 Google Cloud 支持团队联系。

后续步骤