使用 Ingress 设置 HTTP(S) 负载平衡

本教程介绍如何通过配置 Ingress 资源在应用外部 HTTP(S) 负载平衡器的情况下运行 Web 应用。

背景

Google Kubernetes Engine (GKE) 为可公开访问的应用提供了对两种类型的 Cloud Load Balancing 的集成支持:

  • 在资源清单中指定 type:LoadBalancer 时,GKE 会创建一个类型为 LoadBalancerService。 GKE 会进行适当的 Google Cloud API 调用,以创建外部网络负载平衡器内部 TCP/UDP 负载平衡器。 如果您添加 cloud.google.com/load-balancer-type: "Internal" 注释,则 GKE 会创建一个内部 TCP/UDP 负载平衡器;否则,GKE 会创建一个外部网络负载平衡器。

    虽然您可以对 HTTP(S) 流量使用这两种类型的负载平衡器中的任何一种,但它们在 OSI 层 3/4 上运行,并且不知道 HTTP 连接或单个 HTTP 请求和响应。另一个重要特征是请求未代理到目标。

  • 在资源清单中指定 kind:Ingress 时,您需要指示 GKE 创建 Ingress 资源。通过添加注释并支持工作负载和 Service,您可以创建自定义 Ingress 控制器。否则,GKE 会进行适当的 Google Cloud API 调用,以创建外部 HTTP(S) 负载平衡器。负载平衡器的网址映射的主机规则和路径匹配器会引用一个或多个后端服务,其中,每个后端服务对应于一个类型为 NodePort 的 GKE Service,如 Ingress 中引用的那样。每个后端服务的后端是实例组或网络端点组 (NEG)。在配置 Ingress 的过程中,配置容器原生负载平衡时,系统会创建 NEG。对于每个后端服务,GKE 都会根据相应 GKE Service 引用的工作负载的就绪性探测设置创建 Google Cloud 运行状况检查。

    如果要公开在 GKE 上托管的 HTTP(S) 服务,则建议使用 HTTP(S) 负载平衡方法来实现负载平衡。

准备工作

请按照以下步骤启用 Kubernetes Engine API:
  1. 访问 Google Cloud Console 中的 Kubernetes Engine 页面
  2. 创建或选择项目。
  3. 稍作等待,让 API 和相关服务完成启用过程。 此过程可能耗时几分钟。
  4. 确保您的 Google Cloud 项目已启用结算功能。 了解如何确认您的项目已启用结算功能

安装本教程中使用的以下命令行工具:

  • gcloud 用于创建和删除 Kubernetes Engine 集群。gcloud 包含在 Google Cloud SDK 中。
  • kubectl 用于管理 Kubernetes(即 Kubernetes Engine 使用的集群编排系统)。您可以使用 gcloud 安装 kubectl
    gcloud components install kubectl

gcloud 命令行工具设置默认值

如需节省您在 gcloud 命令行工具中输入项目 IDCompute Engine 地区选项的时间,您可以设置默认值:
gcloud config set project project-id
gcloud config set compute/zone compute-zone

创建容器集群

通过运行以下命令创建名为 loadbalancedcluster 的容器集群:

gcloud container clusters create loadbalancedcluster

第 1 步:部署 Web 应用

使用示例 Web 应用容器映像创建一个 Deployment,该示例映像会侦听端口 8080 上的 HTTP 服务器:

  1. 下载 web-deployment.yaml 清单。
  2. 将资源应用到集群:

    kubectl apply -f web-deployment.yaml
    

第 2 步:在内部将 Deployment 公开为 Service

创建一个 Service 资源,使 web 部署可在容器集群中供用户访问。

  1. 下载 web-service.yaml 清单。
  2. 将资源应用到集群:

    kubectl apply -f web-service.yaml
    

    使用此命令创建 NodePort 类型的 Service 时,GKE 会使您的 Service 在集群中所有节点上随机选择的较大端口号(例如 32640)上可用。

  3. 验证是否已创建 Service 且已分配节点端口:

    kubectl get service web
    
    输出:
    NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    web       NodePort   10.35.245.219   <none>        8080:32640/TCP   5m
    

    在以上示例输出结果中,web Service 的节点端口是 32640。另请注意,我们未为此 Service 分配外部 IP 地址。由于默认情况下无法从外部访问 GKE 节点,因此创建此 Service 后,仍无法通过互联网访问您的应用。

要使 HTTP(S) 网络服务器应用可公开访问,您需要创建 Ingress 资源。

第 3 步:创建 Ingress 资源

Ingress 是一种 Kubernetes 资源,它封装了一系列规则和配置,可将外部 HTTP(S) 流量路由到内部服务。

在 GKE 上,Ingress 是使用 Cloud Load Balancing 实现的。当您在集群中创建 Ingress 时,GKE 会创建一个 HTTP(S) 负载平衡器,并将其配置为将流量路由到您的应用。

虽然 Kubernetes Ingress 是一个测试版资源,意味着您对 Ingress 对象的描述随时可能变化,但 GKE 预配的用于实现 Ingress 的 Cloud Load Balancing 负载平衡器可用于生产环境。

下面的配置文件定义了一个用于将流量定向到 web Service 的 Ingress 资源:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: basic-ingress
spec:
  backend:
    serviceName: web
    servicePort: 8080

如需部署此 Ingress 资源,请执行以下操作:

  1. 下载 basic-ingress.yaml 清单。
  2. 将资源应用到集群:

    kubectl apply -f basic-ingress.yaml
    

部署此清单后,Kubernetes 会在您的集群上创建一个 Ingress 资源。GKE Ingress 控制器根据 Ingress 中的信息创建并配置 HTTP(S) 负载平衡器,将端口 80 上的所有外部 HTTP 流量路由到您公开的 web NodePort Service。

第 4 步:访问您的应用

通过运行以下命令找出为应用提供服务的负载平衡器的外部 IP 地址:

kubectl get ingress basic-ingress
输出:
NAME            HOSTS     ADDRESS         PORTS     AGE
basic-ingress   *         203.0.113.12    80        2m

请将浏览器指向应用的外部 IP 地址,并查看如下所示的纯文本 HTTP 响应:

Hello, world!
Version: 1.0.0
Hostname: web-6498765b79-fq5q5

您可以访问 Cloud Console 上的负载平衡,并检查 Ingress 控制器创建的网络资源。

第 5 步:(可选)配置静态 IP 地址

在域名上公开 Web 服务器时,您需要确保应用的外部 IP 地址是不会更改的静态 IP 地址。

默认情况下,GKE 会为通过 Ingress 公开的 HTTP 应用分配临时外部 IP 地址。 临时地址随时可能更改。对于计划长期使用的 Web 应用,您需要使用静态外部 IP 地址

请注意,为 Ingress 资源配置静态 IP 后,删除 Ingress 时将不会删除与之关联的静态 IP 地址。一旦不再打算再次使用所配置的静态 IP 地址,请务必清理该 IP 地址。

选项 1:将现有临时 IP 地址转换为静态 IP 地址

如果已部署 Ingress,则可以通过访问 Cloud Console 上的外部 IP 地址部分,将应用的现有临时 IP 地址转换为预留的静态 IP 地址,而无需更改外部 IP 地址。

选项 2:预留新的静态 IP 地址

  1. 预留名为 web-static-ip静态外部 IP 地址

    gcloud

    gcloud compute addresses create web-static-ip --global
    

    配置连接器

    注意:此步骤需要使用配置连接器。按照安装说明在您的集群上安装配置连接器。

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      name: web-static-ip
    spec:
      location: global
    如需部署此清单,请将它以 compute-address.yaml 的形式下载到您的机器上,然后运行以下命令:
    kubectl apply -f compute-address.yaml

  2. 配置现有 Ingress 资源以使用预留的 IP 地址。将之前使用的 basic-ingress.yaml 清单替换为下面的清单

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: basic-ingress
      annotations:
        kubernetes.io/ingress.global-static-ip-name: "web-static-ip"
    spec:
      backend:
        serviceName: web
        servicePort: 8080
    

    此更改会在 Ingress 上添加一条注释,使其使用名为 web-static-ip 的静态 IP 资源。

  3. 将此修改应用到现有 Ingress:

    kubectl apply -f basic-ingress.yaml
    
  4. 检查外部 IP 地址:

    kubectl get ingress basic-ingress
    

    等待应用的 IP 地址发生更改,以使用 web-static-ip 资源的预留 IP 地址。

    更新现有 Ingress 资源、重新配置负载平衡器并在全局范围传播负载平衡规则可能需要几分钟的时间。完成此操作后,GKE 会释放之前分配给应用的临时 IP 地址。

第 6 步:(可选)在负载平衡器上处理多个应用

您可以通过对 Ingress 配置路由规则,在单个负载平衡器和公共 IP 上运行多个服务。通过在同一 Ingress 上托管多个服务,您就不必为公开给互联网的每一个 Service 创建额外的负载平衡器(此为计费资源)。

使用同一 Web 应用的 2.0 版本再创建一个 Web 服务器 Deployment。

下载 web-deployment-v2.yaml,然后将资源应用到集群:

kubectl apply -f web-deployment-v2.yaml

接下来,在内部将 web2 Deployment 公开给名为 web2 的 NodePort Service 上的集群。

下载 web-service-v2.yaml,然后将资源应用到集群:

kubectl apply -f web-service-v2.yaml

下面的清单描述了具备以下特点的 Ingress 资源:

  • 使用以 /v2/ 开头的路径将请求路由到 web2 Service
  • 将其他所有请求路由到 web Service
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: fanout-ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: web
          servicePort: 8080
      - path: /v2/*
        backend:
          serviceName: web2
          servicePort: 8080

如需部署此清单,请将其保存到 fanout-ingress.yaml,然后运行以下命令:

kubectl create -f fanout-ingress.yaml

部署 Ingress 后,请运行 kubectl get ingress fanout-ingress 来查找集群的公共 IP 地址。

然后,访问该 IP 地址,确定能否在同一负载平衡器上访问这两个应用:

  • 访问 http://<IP_ADDRESS>/ 并注意响应包含 Version: 1.0.0(因为该请求被路由到 web Service)
  • 访问 http://<IP_ADDRESS>/v2/ 并注意响应包含 Version: 2.0.0(因为该请求被路由到 web2 Service)

对于 GKE Ingress 上的 path 字段,仅支持通过 * 字符来进行通配符模式匹配。例如,您的规则可具有类似 /*/foo/bar/* 等的 path 字段。如需了解 path 限制,请参阅网址映射文档

第 7 步:(可选)监控服务的可用性和延迟时间

Google Cloud 正常运行时间检查从用户的角度对应用进行黑盒监控,确定从多个外部 IP 到负载平衡器 IP 地址的延迟时间和可用性。相比之下,Google Cloud 运行状况检查会对 Pod IP 执行内部检查,确定实例级层的可用性。这两项检查是相辅相成的,它们可让您全面了解应用的运行状况。

您可以通过使用 Google Cloud Console、Cloud Monitoring API 或使用 Cloud Monitoring 客户端库来创建正常运行时间检查。 如需了解相关信息,请参阅管理正常运行时间检查。 如需使用 Google Cloud Console 创建正常运行时间检查,请执行以下操作:

  1. 在 Google Cloud Console 中,选择 Monitoring,或点击以下按钮:

    转至 Monitoring

  2. Monitoring 导航窗格中,选择正常运行时间检查,然后点击创建正常运行时间检查

  3. 对于正常运行时间检查的目标,请设置以下字段:

    • 对于协议类型,请选择 TCP
    • 对于资源类型,请选择网址
    • 对于主机名,请输入负载平衡器的 IP 地址。
    • 端口字段中输入负载平衡器的端口号。

    如需查看有关正常运行时间检查中所有字段的完整文档,请参阅创建正常运行时间检查

如需监控正常运行时间检查,您可以创建一个提醒政策或查看正常运行时间检查信息中心。如果您的正常运行时间检查失败,提醒政策可以通过电子邮件或其他渠道通知您。如需了解有关提醒政策的常规信息,请参阅提醒简介

备注

默认情况下,Ingress 通过在 / 路径上发出 GET 请求来执行定期运行状况检查,以确定应用的运行状况,并预期获得 HTTP 200 响应。如果要检查其他路径或预期获得其他响应代码,您可以使用自定义运行状况检查路径

Ingress 支持更高级的用例,例如:

  • 基于名称的虚拟托管:您可以使用 Ingress 对多个域名、子域名重复使用负载平衡器,并在单个 IP 地址和负载平衡器上公开多个 Service。如需了解如何为这些任务配置 Ingress,请查看简单扇出基于名称的虚拟托管示例。

  • HTTPS 终止:您可使用 Cloud Load Balancing 负载平衡器配置 Ingress 来终止 HTTPS 流量。

删除 Ingress 后,Ingress 控制器会自动清理相关资源(预留的静态 IP 地址除外)。

清理

为避免因本教程中使用的资源导致您的 Google Cloud Platform 帐号产生费用,请执行以下操作:

  1. 删除所有手动创建的转发规则和引用 Ingress 的目标代理:

    引用 Ingress 控制器托管的网址映射的悬垂目标代理将导致 GKE 1.15.4-gke.22+ 版本中的 Ingress 删除失败。您可以检查 Ingress 资源,以查找包含类似于以下内容错误消息的事件:

     Error during GC: error running load balancer garbage collection routine: googleapi: Error 400: The url_map resource 'projects/project-id/global/urlMaps/k8s2-um-tlw9rhgp-default-my-ingress-9ifnni82' is already being used by 'projects/project-id/global/targetHttpsProxies/k8s2-um-tlw9rhgp-default-my82-target-proxy', resourceInUseByAnotherResource
     

    在上面的示例错误消息中,k8s2-um-tlw9rhgp-default-my82-target-proxy 是一个手动创建的目标 https 代理,该代理仍然引用由 Ingress 控制器创建和管理的网址映射 k8s2-um-tlw9rhgp-default-my-ingress-9ifnni82

    因此,在删除 Ingress 之前,需要先删除这些手动创建的前端资源(包括转发规则和目标代理)。

  2. 删除 Ingress:此操作将释放临时外部 IP 地址和与您的应用关联的负载平衡资源:

    kubectl delete ingress basic-ingress

    如果您已按照“第 6 步”进行操作,请运行以下命令删除该 Ingress:

    kubectl delete ingress fanout-ingress

  3. 删除静态 IP 地址:仅在您执行了第 5 步的情况下执行此操作。

    • 如果您已按照第 5 步中的“选项 1”将现有临时 IP 地址转换为静态 IP 地址,请访问 Cloud Console 来删除该静态 IP 地址。

    • 如果您已按照第 5 步中的“选项 2”进行操作,则请运行以下命令删除该静态 IP 地址:

      gcloud compute addresses delete web-static-ip --global
  4. 删除集群:此操作将删除容器集群的计算节点以及集群中的 Deployment 等其他资源:

    gcloud container clusters delete loadbalancedcluster

后续步骤