使用内部 TCP/UDP 负载平衡器

本页面介绍如何在 Google Kubernetes Engine 上创建 Compute Engine 内部 TCP/UDP 负载平衡器

概览

内部 TCP/UDP 负载平衡可让使用相同 VPC 网络并位于同一 Google Cloud 地区的集群外部应用访问集群的服务。例如,假设您的集群位于 us-west1 地区,并且您需要使其某项服务可供在该地区内运行的 Compute Engine 虚拟机实例通过同一 VPC 网络访问。

您可以创建内部 TCP/UDP 负载平衡器,方法是创建 Service 资源并添加 cloud.google.com/load-balancer-type: "Internal" 注释和 type: LoadBalancer 规范。以下说明和示例重点介绍如何执行此操作。

如果没有内部 TCP/UDP 负载平衡,您需要设置外部负载平衡器和防火墙规则,以使应用可从集群外部进行访问。

内部 TCP/UDP 负载平衡会为 Service 创建一个内部 IP 地址,用于接收来自同一 VPC 网络和计算地区内各个客户端的流量。如果您启用全球访问,则同一 VPC 网络中任意地区的客户端均可访问 Service。 此外,使用 VPC 网络对等互连连接到 LoadBalancer 网络的 VPC 网络中的客户端也可以访问 Service。

价格

费用按照 Compute Engine 的价格模式收取。如需了解详情,请参阅负载平衡和转发规则价格以及 Google Cloud 价格计算器上的 Compute Engine 页面。

准备工作

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

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

  1. 运行 gcloud init 并按照说明操作:

    gcloud init

    如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

    gcloud init --console-only
  2. 按照说明授权 gcloud 使用您的 Google Cloud 帐号。
  3. 创建新配置或选择现有配置。
  4. 选择 Google Cloud 项目。
  5. 选择默认的 Compute Engine 区域。

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project project-id
  • 如果您使用的是可用区级集群,请设置默认计算可用区
    gcloud config set compute/zone compute-zone
  • 如果您使用的是区域级集群,请设置默认计算区域
    gcloud config set compute/region compute-region
  • gcloud 更新到最新版本:
    gcloud components update

创建一个 Deployment

以下清单说明了一个运行 Hello World 应用的 3 个副本的 Deployment。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:2.0"

有关此示例应用的源代码和 Dockerfile,请参阅 GitHub。 由于未指定 PORT 环境变量,因此容器将侦听默认端口 8080。

要创建 Deployment,请根据清单创建 my-deployment.yaml 文件,然后使用 shell 或终端窗口运行以下命令:

kubectl apply -f my-deployment.yaml

创建内部 TCP 负载平衡器

以下部分介绍了如何使用 Service 创建内部 TCP 负载平衡器。

编写 Service 配置文件

以下示例展示了用于创建内部 TCP 负载平衡器的 Service:

apiVersion: v1
kind: Service
metadata:
  name: ilb-service
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
  labels:
    app: hello
spec:
  type: LoadBalancer
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

最低 Service 要求

您的清单必须包含以下内容:

  • Service 的 name,在本例中为 ilb-service
  • cloud.google.com/load-balancer-type: "Internal" 注释,用于指定要配置内部 TCP/UDP 负载平衡器。
  • type: LoadBalancer
  • spec: selector 字段,用于指定 Service 应针对的 Pod,例如 app: hello
  • port(用于公开 Service 的端口)和 targetPort(容器侦听的端口)。

部署 Service

要创建内部 TCP 负载平衡器,请根据清单创建 my-service.yaml 文件,然后使用 shell 或终端窗口运行以下命令:

kubectl apply -f my-service.yaml

检查 Service

部署后,检查 Service 以验证其是否已成功配置。

获取有关 Service 的详细信息:

kubectl get service ilb-service --output yaml

在输出中,您可以在 status.loadBalancer.ingress 下看到内部负载平衡器的 IP 地址。请注意,这与 clusterIP 的值不同。在此示例中,负载平衡器的 IP 地址为 10.128.15.193

apiVersion: v1
kind: Service
metadata:
  ...
  labels:
    app: hello
  name: ilb-service
  ...
spec:
  clusterIP: 10.0.9.121
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30835
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: hello
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 10.128.15.193

具有 app: hello 标签的任何 Pod 都是此 Service 的成员。这些 Pod 可以是发送到内部负载平衡器的请求的最终接收者。

客户端使用 Service 清单的 port 字段中指定的 loadBalancer IP 地址和 TCP 端口调用 Service。请求将转发到 targetPort 字段中指定的 TCP 端口上的其中一个成员 Pod。因此,对于上述示例,客户端在 TCP 端口 80 上调用 IP 地址为 10.128.15.193 的 Service。请求将转发到 TCP 端口 8080 上的其中一个成员 Pod。请注意,该成员 Pod 必须具有一个侦听端口 8080 的容器。

nodePort 值 30835 是额外的;与内部负载平衡器无关。

查看负载平衡器的转发规则

内部负载平衡器是以转发规则的形式实现的。 转发规则包含后端服务,该后端服务具有实例组

上述示例中的内部负载平衡器地址 10.128.15.193 与转发规则地址相同。要查看实现内部负载平衡器的转发规则,请先列出项目中的所有转发规则:

gcloud compute forwarding-rules list --filter="loadBalancingScheme=INTERNAL"

在输出中,查找与内部负载平衡器具有相同地址(在此示例中为 10.128.15.193)的转发规则。

NAME                          ... IP_ADDRESS  ... TARGET
...
aae3e263abe0911e9b32a42010a80008  10.128.15.193   us-central1/backendServices/aae3e263abe0911e9b32a42010a80008

输出会显示关联的后端服务(在此示例中为 ae3e263abe0911e9b32a42010a80008)。

描述此后端服务:

gcloud compute backend-services describe aae3e263abe0911e9b32a42010a80008 --region us-central1

输出会显示关联的实例组(在此示例中为 k8s-ig--2328fa39f4dc1b75):

backends:
- balancingMode: CONNECTION
  group: .../us-central1-a/instanceGroups/k8s-ig--2328fa39f4dc1b75
...
kind: compute#backendService
loadBalancingScheme: INTERNAL
name: aae3e263abe0911e9b32a42010a80008
...

Service 抽象的工作原理

当数据包由您的转发规则处理时,会被转发到您的某个集群节点。当数据包到达该集群节点时,地址和端口会如下所示:

目标 IP 地址 转发规则,在此示例中为 10.128.15.193
目标 TCP 端口 Service port 字段,在此示例中为 80

请注意,转发规则(即内部负载平衡器)不会更改目标 IP 地址或目标端口。集群节点上的 iptables 规则会将数据包路由到相应的 Pod。iptables 规则会将目标 IP 地址更改为 Pod IP 地址,并将目标端口更改为 Service 的 targetPort 值(在此示例中为 8080)。

验证内部 TCP 负载平衡器

通过 SSH 登录到虚拟机实例,然后运行以下命令:

curl load-balancer-ip

其中,load-balancer-ip 是您的 LoadBalancer Ingress IP 地址。

响应会显示 hello-app 的输出:

Hello, world!
Version: 2.0.0
Hostname: hello-app-77b45987f7-pw54n

从同一 VPC 网络外部或同一地区外部运行此命令会导致超时错误。如果您配置了全球访问,则同一 VPC 网络中任何地区内的客户端都可以访问负载平衡器。

清理

您可以使用 kubectl delete 或 Cloud Console 删除 Deployment 和 Service。

kubectl

删除 Deployment

要删除 Deployment,请运行以下命令:

kubectl delete deployment hello-app

删除 Service

要删除 Service,请运行以下命令:

kubectl delete service ilb-service

控制台

删除 Deployment

要删除 Deployment,请执行以下步骤:

  1. 访问 Cloud Console 中的 Google Kubernetes Engine“工作负载”菜单。

    访问“工作负载”菜单

  2. 从该菜单中选择所需的工作负载。

  3. 点击删除

  4. 从确认对话框菜单中,点击删除

删除 Service

要删除 Service,请执行以下步骤:

  1. 访问 Cloud Console 中的 Google Kubernetes Engine“服务”菜单。

    访问“服务”菜单

  2. 从该菜单中选择所需的 Service。

  3. 点击删除

  4. 从确认对话框菜单中,点击删除

关于现有 Ingress 的注意事项

内部 TCP/UDP 负载平衡器和使用 UTILIZATION 平衡模式的 Ingress 不能同时使用。要同时使用 Ingress 和内部 TCP/UDP 负载平衡,Ingress 必须使用 RATE 平衡模式。

如果集群的现有 Ingress 资源是使用 Kubernetes 1.7.1 或更低版本创建的,则该集群与内部 TCP/UDP 负载平衡器不兼容。 通过 Kubernetes Ingress 资源对象创建的早期 BackendService 资源是在未指定平衡模式的情况下创建的。对于 HTTP 负载平衡器,API 默认使用 UTILIZATION 平衡模式。但是,内部 TCP/UDP 负载平衡器不能指向具有其他使用 UTILIZATION 平衡模式的负载平衡器的实例组。

确定 Ingress 平衡模式

要确定您使用的 Ingress 平衡模式,请使用 shell 或终端窗口运行以下命令:

GROUPNAME=`kubectl get configmaps ingress-uid -o jsonpath='k8s-ig--{.data.uid}' --namespace=kube-system`
gcloud compute backend-services list --format="table(name,backends[].balancingMode,backends[].group)" | grep $GROUPNAME

这些命令导出 shell 变量 GROUPNAME,该变量会获取集群的实例组名称。然后,系统会对项目的 Compute Engine backend service 资源进行轮询,并根据 $GROUPNAME 的内容缩小结果的范围。

输出类似于以下内容:

k8s-be-31210--...  [u'RATE']       us-central1-b/instanceGroups/k8s-ig--...
k8s-be-32125--...  [u'RATE']       us-central1-b/instanceGroups/k8s-ig--...

如果输出返回 RATE 条目或返回零个条目,则说明内部负载平衡器兼容,您不需要进行额外操作。

如果输出返回带有 UTILIZATION 标记的条目,则说明您的 Ingress 不兼容。

要更新 Ingress 资源以使其与内部 TCP/UDP 负载平衡器兼容,您可以新建一个运行 Kubernetes 1.7.2 或更高版本的集群,然后将服务迁移到该集群。

Service 参数

如需详细了解您可以配置的负载平衡器参数,请参阅配置 TCP/UDP 负载平衡。此外,内部 LoadBalancer 服务还支持以下附加参数:

功能 摘要 Service 字段 GKE 版本支持
负载平衡器子网 指定负载平衡器应通过哪个子网自动预配 IP metadata:annotations: networking.gke.io/internal-load-balancer-subnet Beta 版的 GKE 1.17 及更高版本和 1.16.8-gke.10 及更高版本
正式版的 GKE 1.17.9-gke.600 及更高版本
全球访问权限 允许各 GCP 地区的客户端访问 TCP/UDP 负载平衡器 VIP 地址 metadata:annotations: networking.gke.io/internal-load-balancer-allow-global-access Beta 版的 GKE 1.16 及更高版本
正式版的 GKE 1.17.9-gke.600 及更高版本

负载平衡器子网

默认情况下,GKE 将使用节点子网范围部署内部 TCP/UDP 负载平衡器。用户可以使用 networking.gke.io/internal-load-balancer-subnet 注释按服务指定子网。 这对于在内部负载平衡器 IP 与节点 IP 之间单独设置防火墙或跨多个 GKE 集群共享同一 Service 子网非常有用。此参数仅与内部 TCP/UDP LoadBalancer Service 相关。

子网必须存在才能被 Service 资源引用,因为 GKE 不会管理子网本身的生命周期。子网还必须与 GKE 集群位于同一 VPC 和地区中。在本步骤中,它是从 GKE 带外创建的:

gcloud compute networks subnets create gke-vip-subnet \
    --network=default \
    --range=10.23.0.0/24 \
    --region=us-central1

以下 Service 定义使用 internal-load-balancer-subnet 按名称引用子网。默认情况下,系统会自动选择子网的可用 IP。您还可以指定 loadBalancerIP,但它必须是受引用子网的一部分。

目前有多种方法可以共享此内部负载平衡器子网以实现不同的用例:

  • 同一集群中的 Service 组有多个子网
  • 集群中所有 Service 只有一个子网
  • 跨多个集群和多个 Service 共享一个子网
apiVersion: v1
kind: Service
metadata:
  name: ilb-service
  annotations:
    networking.gke.io/load-balancer-type: "Internal"
    networking.gke.io/internal-load-balancer-subnet: "gke-vip-subnet"
  labels:
    app: hello
spec:
  type: LoadBalancer
  loadBalancerIP: 10.23.0.15
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

全球访问权限

全球访问是内部 LoadBalancer Service 的一个可选参数,允许来自您的 VPC 网络内任意地区的客户端访问内部 TCP/UDP 负载平衡器。如果没有全球访问,来自 VPC 网络中各个客户端的流量必须与负载平衡器位于同一地区。全球访问允许任何地区内的客户端访问负载平衡器。后端实例仍必须与负载平衡器位于同一地区内。

请使用以下注释为每项服务启用全球访问:networking.gke.io/internal-load-balancer-allow-global-access: "true"

旧式网络不支持全球访问。跨多个地区使用全球访问时,我们会收取常规的地区间流量费用。请参阅网络价格,了解各地区间出站流量的网络价格信息。全球访问权限在 Beta 版的 GKE 集群 1.16 及更高版本和正式版的 1.17.9-gke.600 及更高版本中提供。

共享 IP(Beta 版)

内部 TCP/UDP 负载平衡器允许在多个转发规则之间共享虚拟 IP 地址。这对于扩充同一 IP 上的并发端口数或接受同一 IP 上的 UDP 和 TCP 流量非常有用。它允许每个 IP 地址最多有 50 个公开端口。具有内部 LoadBalancer Service 的 GKE 集群会以原生方式支持共享 IP。部署时,Service 的 loadBalancerIP 字段用于指示应在 Service 之间共享的 IP。

限制

多个负载平衡器的共享 IP 具有以下限制和功能:

  • 每个 Service(或转发规则)最多可以有五个端口。
  • 最多 10 个服务(转发规则)可以共享一个 IP 地址。这会导致每个共享 IP 最多 50 个端口。
  • 协议/端口元组在共享同一 IP 的 Service 之间不能重叠。
  • 同一共享 IP 支持将仅使用 TCP 的 Service 和仅使用 UDP 的服务相组合,但您无法在同一 Service 中公开 TCP 端口和 UDP 端口。

启用共享 IP

如需允许内部 LoadBalancer Service 共享公共 IP,请按以下步骤操作:

  1. 使用 --purpose SHARED_LOADBALANCER_VIP 创建静态内部 IP。必须创建一个具有此用途的 IP 地址,才能共享此 IP 地址。

  2. loadBalancerIP 字段中使用此静态 IP 的内部 LoadBalancer Service 最多可部署 10 个。内部 TCP/UDP 负载平衡器由 GKE 服务控制器进行协调,并使用同一前端 IP 进行部署。

以下示例演示了如何执行此过程,以针对同一内部负载平衡器 IP 支持多个 TCP 和 UDP 端口。

  1. 在 GKE 集群所在的地区中创建静态 IP。子网必须是负载平衡器使用的子网,默认情况下是 GKE 集群节点 IP 使用的子网。

    gcloud beta compute addresses create internal-10-128-2-98 \
        --region=us-central1 \
        --subnet=default \
        --addresses=10.128.2.98 \
        --purpose=SHARED_LOADBALANCER_VIP
    
  2. 将以下 TCP Service 配置保存到名为 tcp-service.yaml 的文件中,然后部署到集群。它使用共享 IP 10.128.2.98

    apiVersion: v1
    kind: Service
    metadata:
      name: tcp-service
      namespace: default
      annotations:
        cloud.google.com/load-balancer-type: "Internal"
    spec:
      type: LoadBalancer
      loadBalancerIP: 10.128.2.98
      selector:
        app: myapp
      ports:
      - name: 8001-to-8001
        protocol: TCP
        port: 8001
        targetPort: 8001
      - name: 8002-to-8002
        protocol: TCP
        port: 8002
        targetPort: 8002
      - name: 8003-to-8003
        protocol: TCP
        port: 8003
        targetPort: 8003
      - name: 8004-to-8004
        protocol: TCP
        port: 8004
        targetPort: 8004
      - name: 8005-to-8005
        protocol: TCP
        port: 8005
        targetPort: 8005
    
  3. 针对您的集群应用此 Service 定义:

    kubectl apply -f tcp-service.yaml
    
  4. 将以下 UDP Service 配置保存到名为 udp-service.yaml 的文件中,然后进行部署。它还使用共享 IP 10.128.2.98

    apiVersion: v1
    kind: Service
    metadata:
      name: udp-service
      namespace: default
      annotations:
        cloud.google.com/load-balancer-type: "Internal"
    spec:
      type: LoadBalancer
      loadBalancerIP: 10.128.2.98
      selector:
        app: my-udp-app
      ports:
      - name: 9001-to-9001
        protocol: UDP
        port: 9001
        targetPort: 9001
      - name: 9002-to-9002
        protocol: UDP
        port: 9002
        targetPort: 9002
    
  5. 针对您的集群应用此文件:

    kubectl apply -f udp-service.yaml
    
  6. 通过列出这些规则并进行静态 IP 过滤,验证是否已在各负载平衡 (LB) 转发规则之间共享 VIP。这表明有 UDP 和 TCP 转发规则都在侦听共享 IP 地址 10.128.2.98 上的 7 个不同端口。

    gcloud compute forwarding-rules list | grep 10.128.2.98
    ab4d8205d655f4353a5cff5b224a0dde                         us-west1   10.128.2.98     UDP          us-west1/backendServices/ab4d8205d655f4353a5cff5b224a0dde
    acd6eeaa00a35419c9530caeb6540435                         us-west1   10.128.2.98     TCP          us-west1/backendServices/acd6eeaa00a35419c9530caeb6540435
    

内部 TCP/UDP 负载平衡器所存在的限制

  • 对于运行 Kubernetes 1.7.3 版及更早版本的集群,您只能将内部 TCP/UDP 负载平衡器与自动模式子网配合使用,但对于 Kubernetes 1.7.4 版及更高版本,除了自动模式子网,您还可以将内部负载平衡器与自定义模式子网配合使用。
  • 对于运行 Kubernetes 1.7.X 或更高版本的集群,虽然 clusterIP 保持不变,但内部 TCP/UDP 负载平衡器无法使用保留的 IP 地址。spec.loadBalancerIP 字段仍然可以使用未用的 IP 地址进行定义,以分配特定的内部 IP 地址。更改端口、协议或会话粘性可能会导致这些 IP 地址发生变化。

内部 UDP 负载平衡器所存在的限制

  • 内部 UDP 负载平衡器不支持使用 sessionAffinity: ClientIP

限制

添加了 cloud.google.com/load-balancer-type: Internal 注释的 type: Loadbalancer 类型 Kubernetes Service 会创建一个针对该 Kubernetes Service 的 ILB。此类 Service 的数量受到可在 VPC 网络中创建的内部转发规则数量的限制。如需了解详情,请参阅每个网络的限制

在 GKE 集群中,内部转发规则指向集群中的所有节点。集群中的每个节点都是 ILB 的一个后端虚拟机。 无论虚拟机与实例组的关联方式如何,一个 ILB 的最大后端虚拟机数量均为 250。因此,具有 ILB 的 GKE 集群中的最大节点数为 250。如果为集群启用了自动调节功能,则必须确保自动调节不会将集群扩容到超过 250 个节点。

如需详细了解这些限制,请参阅 VPC 资源配额

后续步骤