通过 Ingress 配置容器原生负载平衡

本页面介绍了如何在 Google Kubernetes Engine (GKE) 中使用容器原生负载平衡。利用容器原生负载平衡,负载平衡器能够直接定位 Kubernetes Pod,还能将流量均匀分发给 Pod。

如需了解容器原生负载平衡的优势、要求和限制,请参阅容器原生负载平衡

使用容器原生负载平衡

以下几个部分将引导您完成 GKE 上的容器原生负载平衡配置。 请注意,对于 GKE 集群 1.17 和更高版本,以及在特定条件下,容器原生负载平衡是默认负载平衡,不需要明确的 cloud.google.com/neg: '{"ingress": true}' Service 注释。

创建 VPC 原生集群

如需使用容器原生负载平衡,必须创建已启用别名 IP 地址的集群

例如,以下命令会使用自动预配的子网在地区 us-central1-a 中创建一个集群 neg-demo-cluster

gcloud container clusters create neg-demo-cluster \
    --enable-ip-alias \
    --create-subnetwork="" \
    --network=default \
    --zone=us-central1-a

创建 Deployment

接下来,将工作负载部署到集群。

以下示例 Deployment neg-demo-app 运行某容器化 HTTP 服务器的单个实例。如果您使用的 GKE 版本中提供了 Pod 就绪性反馈,我们建议您使用利用该反馈的工作负载。如需了解详情和 GKE 版本要求,请参阅 Pod 就绪性。请考虑升级您的集群以使用 Pod 就绪性反馈。

使用 Pod 就绪性反馈

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
        ports:
        - containerPort: 9376
          protocol: TCP
  

使用硬编码延迟

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
      # Note: The following line is necessary only on clusters running GKE v1.11 and lower.
      # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts
        ports:
        - containerPort: 9376
          protocol: TCP
      terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
  

在此 Deployment 中,每个容器都运行一个 HTTP 服务器。该 HTTP 服务器简单地返回应用服务器的主机名(运行服务器所在的 Pod 的名称)作为响应。

将此清单保存为 neg-demo-app.yaml,然后通过运行以下命令创建 Deployment:

kubectl apply -f neg-demo-app.yaml

为容器原生负载平衡器创建 Service

创建 Deployment 后,需要将其 Pod 分组到 Service 中。

以下示例 Service neg-demo-svc 会定位您在上一个部分中创建的示例 Deployment:

apiVersion: v1
kind: Service
metadata:
  name: neg-demo-svc # Name of Service
  annotations:
    cloud.google.com/neg: '{"ingress": true}' # Creates a NEG after an Ingress is created
spec: # Service's specification
  type: ClusterIP
  selector:
    run: neg-demo-app # Selects Pods labelled run: neg-demo-app
  ports:
  - port: 80 # Service's port
    protocol: TCP
    targetPort: 9376

该 Service 的注释 cloud.google.com/neg: '{"ingress": true}' 会启用容器原生负载平衡。但是,在为该 Service 创建 Ingress 之前,不会创建负载平衡器。

将此清单保存为 neg-demo-svc.yaml,然后通过运行以下命令创建 Service:

kubectl apply -f neg-demo-svc.yaml

为 Service 创建 Ingress

以下示例 Ingress neg-demo-ing 会定位您创建的 Service:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: neg-demo-ing
spec:
  backend:
    serviceName: neg-demo-svc # Name of the Service targeted by the Ingress
    servicePort: 80 # Should match the port used by the Service

将此清单保存为 neg-demo-ing.yaml,然后通过运行以下命令创建 Ingress:

kubectl apply -f neg-demo-ing.yaml

创建 Ingress 后,将在项目中创建 HTTP(S) 负载平衡器,并在集群运行的每个地区中创建 NEG。NEG 中的端点和 Service 的端点会保持同步。

验证 Ingress

部署了工作负载,将其 Pod 分组到 Service 中,并为 Service 创建了 Ingress 后,您应验证 Ingress 是否已成功预配容器原生负载平衡器。

如需检索 Ingress 的状态,请运行以下命令:

kubectl describe ingress neg-demo-ing

在命令输出中,查找 ADDCREATE 事件:

Events:
Type     Reason   Age                From                     Message
----     ------   ----               ----                     -------
Normal   ADD      16m                loadbalancer-controller  default/neg-demo-ing
Normal   Service  4s                 loadbalancer-controller  default backend set to neg-demo-svc:32524
Normal   CREATE   2s                 loadbalancer-controller  ip: 192.0.2.0

测试负载平衡器的功能

以下几个部分说明如何测试容器原生负载平衡器的功能。

访问 Ingress 的 IP 地址

等待几分钟,让 HTTP(S) 负载平衡器完成配置。

您可以通过访问 Ingress 的 IP 地址来验证容器原生负载平衡器是否正常运行。

如需获取 Ingress 的 IP 地址,请运行以下命令:

kubectl get ingress neg-demo-ing

在命令输出中,Ingress 的 IP 地址显示在 ADDRESS 列中。在网络浏览器中访问 IP 地址。

检查后端服务的运行状况

您还可以获取负载平衡器的后端服务的运行状况。

首先,获取项目中运行的后端服务的列表:

gcloud compute backend-services list

复制包含 Service 名称的后端名称,例如 neg-demo-svc。然后,获取后端服务的运行状况:

gcloud compute backend-services get-health backend-service-name --global

验证 Ingress 的功能

您可以采用另一种方法来测试负载平衡器是否按预期运行,也就是扩缩示例 Deployment,将测试请求发送到 Ingress,并验证响应的副本数量是否正确。

以下命令会将 neg-demo-app Deployment 从一个实例扩大到两个实例:

kubectl scale deployment neg-demo-app --replicas 2

请等待几分钟,直到发布完成。要验证发布是否已完成,请运行以下命令:

kubectl get deployment neg-demo-app

在命令输出中,确认有两个可用的副本:

NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
neg-demo-app   2         2         2            2           26m

然后,运行以下命令以计算来自负载平衡器的不同响应的数量:

for i in `seq 1 100`; do \
  curl --connect-timeout 1 -s ip-address && echo; \
done  | sort | uniq -c

其中,ip-address 是 Ingress 的 IP 地址。您可以运行 kubectl describe ingress neg-demo-ing 来获取 Ingress 的 IP 地址。

在命令输出中,您会注意到不同响应的数量与副本的数量相同,这表明所有后端 Pod 都在处理流量:

44 neg-demo-app-7f7dfd7bc6-dcn95
56 neg-demo-app-7f7dfd7bc6-jrmzf

清理

完成本页面上的任务后,请按照以下步骤移除资源,以防止您的帐号产生不必要的费用:

删除集群

gcloud

gcloud container clusters delete neg-demo-cluster

Console

  1. 访问 Cloud Console 中的 Google Kubernetes Engine 菜单。

    访问 Google Kubernetes Engine 菜单

  2. 选择 neg-demo-cluster

  3. 点击删除

问题排查

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

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

  • 您可以在服务的 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 地址,请参阅使用别名 IP 地址创建 VPC 原生集群

流量未到达端点

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

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

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

解决方法

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

如需了解详情,请参阅有关 Pod 终止的文档以及有关 Pod 终止最佳做法的这篇博文

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

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

gcloud compute backend-services list

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

gcloud compute backend-services get-health backend-service-name

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

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

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

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

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

停止发布

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

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

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

kubectl get my-pod -o wide

检查 READINESS GATES 列。

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

kubectl get my-pod -o yaml

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

解决方法

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

已知问题

Google Kubernetes Engine 上的容器原生负载平衡存在以下已知问题:

垃圾回收不完整

Google Kubernetes Engine 每两分钟对容器原生负载平衡器执行一次垃圾回收操作。如果在完全移除负载平衡器之前删除了集群,则需要手动删除负载平衡器的 NEG。

通过运行以下命令查看项目中的 NEG:

gcloud compute network-endpoint-groups list

在命令输出中,查找相关的 NEG。

如需删除 NEG,请运行以下命令,其中 neg 是 NEG 的名称:

gcloud compute network-endpoint-groups delete neg

使工作负载发布与端点传播保持一致

将工作负载部署到集群或更新现有工作负载时,容器原生负载平衡器传播新端点所需的时间可能比完成工作负载发布所需的时间长。您在本指南中部署的示例 Deployment 使用两个字段来使其发布与端点的传播保持一致:terminationGracePeriodSecondsminReadySeconds

terminationGracePeriodSeconds 允许 Pod 等待连接在某个 Pod 被安排删除后终止,从而能够正常关闭。

minReadySeconds 会在创建 Pod 后添加延迟时段。您需要指定新的 Pod 在被视为可用前应处于 Ready 状态(没有任何容器崩溃)的秒数下限。

您应将工作负载的 minReadySecondsterminationGracePeriodSeconds 值配置为 60 秒或更长时间,以确保服务不会因为工作负载发布而中断。

terminationGracePeriodSeconds 在所有 Pod 规范中均可用;minReadySeconds 可用于 Deployment 和 DaemonSet。

如需详细了解如何微调发布,请参阅 RollingUpdateStrategy

未遵循 Pod readinessProbe 中的 initialDelaySeconds

您可能希望容器原生负载平衡器遵循 Pod 的 readinessProbe 中的 initialDelaySeconds 配置;但是,readinessProbe 由 kubelet 实现,并且 initialDelaySeconds 配置(而不是容器原生负载平衡器)控制 kubelet 运行状况检查。容器原生负载平衡有自己的负载平衡运行状况检查。

后续步骤