配置适用于内部应用负载均衡器的 Ingress


本页面介绍如何在 Google Kubernetes Engine (GKE) 中设置和使用适用于内部应用负载均衡器的 Ingress。Ingress 通过 GKE Ingress 控制器为内部负载均衡提供内置支持。

如需详细了解适用于内部应用负载均衡器的 Ingress 支持哪些功能,请参阅 Ingress 功能。您也可以参阅适用于内部应用负载均衡器的 Ingress 来详细了解适用于内部应用负载均衡器的 Ingress 的工作原理。

准备工作

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

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

使用要求

适用于内部应用负载均衡器的 Ingress 具有以下要求:

  • 您的集群使用的 GKE 版本必须高于 1.16.5-gke.10。
  • 您的集群必须是 VPC 原生集群
  • 集群必须启用 HttpLoadBalancing 插件。默认情况下,此插件处于启用状态。您不得将其停用。
  • 您必须使用网络端点组 (NEG) 作为服务的后端。

部署适用于内部应用负载均衡器的 Ingress

以下练习介绍了如何部署适用于内部应用负载均衡器的 Ingress:

  1. 准备环境
  2. 创建集群
  3. 部署应用
  4. 部署 Service
  5. 部署 Ingress
  6. 验证部署
  7. 删除 Ingress 资源

准备环境

您必须先准备网络环境,以便将负载均衡器代理部署到指定区域,然后才能通过 Kubernetes Ingress API 部署负载均衡器资源。

创建代理专用子网:

gcloud compute networks subnets create proxy-only-subnet \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=COMPUTE_REGION \
    --network=NETWORK_NAME \
    --range=10.129.0.0/23

替换以下内容:

如需了解详情,请参阅配置代理专用子网

创建防火墙规则

Ingress 控制器不会创建防火墙规则来允许来自代理子网中的负载均衡器代理的连接。您必须手动创建此防火墙规则。但是,Ingress 控制器会创建防火墙规则来允许用于 Google Cloud 健康检查的入站流量。

创建一条防火墙规则以允许从代理专用子网中的负载均衡器代理连接到 pod 监听端口:

gcloud compute firewall-rules create allow-proxy-connection \
    --allow=TCP:CONTAINER_PORT \
    --source-ranges=10.129.0.0/23 \
    --network=NETWORK_NAME

CONTAINER_PORT 替换为 Pod 监听的端口的值,例如 9376

创建集群

在本部分中,您将创建一个 VPC 原生集群,以便与适用于内部应用负载均衡器的 Ingress 搭配使用。您可以使用 Google Cloud CLI 或 Google Cloud 控制台创建此集群。

gcloud

在代理专用子网所在的网络中创建集群:

gcloud container clusters create-auto CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --network=NETWORK_NAME

替换以下内容:

  • CLUSTER_NAME:集群的名称。
  • COMPUTE_LOCATION:集群的 Compute Engine 位置。您必须使用上一部分中创建的代理子网所在的位置。

控制台

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

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. 在 Autopilot 部分中,点击配置

  4. 集群基本信息部分,完成以下操作:

    1. 输入集群的名称
    2. 位置类型部分,为集群选择 Compute Engine 区域。您必须使用上一部分中创建的代理子网所在的区域。
  5. 在导航窗格中,点击网络

  6. 网络列表中,选择要在其中创建集群的网络。此网络必须与代理子网位于同一 VPC 网络中。

  7. 节点子网列表中,选择您创建的代理子网

  8. 点击创建

部署 Web 应用

在本部分中,您将创建 Deployment

如需创建 Deployment,请执行以下操作:

  1. 将以下示例清单保存为 web-deployment.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: hostname
      name: hostname-server
    spec:
      selector:
        matchLabels:
          app: hostname
      minReadySeconds: 60
      replicas: 3
      template:
        metadata:
          labels:
            app: hostname
        spec:
          containers:
          - image: registry.k8s.io/serve_hostname:v1.4
            name: hostname-server
            ports:
            - containerPort: 9376
              protocol: TCP
          terminationGracePeriodSeconds: 90
    

    此清单描述了一个在端口 9376 上监听 HTTPS 服务器的 Deployment。此 Deployment 还将为您的应用管理 Pod。每个 Pod 运行一个具有 HTTPS 服务器的应用容器,该 HTTPS 服务器会将应用服务器的主机名作为响应返回。Pod 的默认主机名就是 Pod 的名称。该容器还会处理正常终止。

  2. 将清单应用于集群:

    kubectl apply -f web-deployment.yaml
    

将 Service 部署为网络端点组 (NEG)

在本部分中,您将创建 Service 资源。该 Service 资源会根据后端容器的标签选择容器,以便 Ingress 控制器将这些容器编程为后端端点。如需使用适用于内部应用负载均衡器的 Ingress,您必须使用 NEG 作为后端。该功能不支持将实例组用作后端。由于需要使用 NEG 后端,因此在您部署通过 Ingress 公开的 Service 时,必须使用以下 NEG 注解:

annotations:
  cloud.google.com/neg: '{"ingress": true}'

如果满足以下所有条件,系统便会自动为您的 Service 添加 cloud.google.com/neg: '{"ingress": true}' 注解:

  • 您使用的是 VPC 原生集群。
  • 您未使用共享 VPC。
  • 您未使用 GKE 网络政策

系统会使用名为 neg-annotation.config.common-webhooks.networking.gke.ioMutatingWebhookConfiguration 自动添加注解。您可以使用以下命令检查 MutatingWebhookConfiguration 是否存在:

kubectl get mutatingwebhookconfigurations

通过使用 NEG,Ingress 控制器可以执行容器原生负载均衡。 流量负载会从 Ingress 代理直接平衡到 Pod IP 地址,而不是遍历节点 IP 地址或 kube-proxy 网络。此外,系统会实施 Pod 就绪性门控措施,以便从负载均衡器的角度(而不仅仅是从 Kubernetes 就绪性和活跃检查角度)确定 Pod 的运行状况。Pod 就绪性门控可确保流量在 Pod 启动、Pod 丢失或节点丢失等生命周期事件期间不会被丢弃。

如果您未添加 NEG 注解,则会在 Ingress 对象上收到警告,其会阻止您配置内部应用负载均衡器。如果未添加 NEG 注解,系统也会在 Ingress 上生成一个 Kubernetes 事件。以下消息是事件消息的示例:

Message
-------
error while evaluating the ingress spec: could not find port "8080" in service "default/no-neg-svc"

在 Ingress 引用该 Service 之前,不会创建 NEG。只有在 Ingress 及其引用的 Service 都已经存在的情况下,NEG 才会出现在 Compute Engine 中。NEG 是一种可用区资源;对于多可用区集群,每个可用区的每项 Service 都将创建一个 NEG。

如需创建 Service,请执行以下操作:

  1. 将以下示例清单保存为 web-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: hostname
      namespace: default
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
    spec:
      ports:
      - name: host1
        port: 80
        protocol: TCP
        targetPort: 9376
      selector:
        app: hostname
      type: ClusterIP
    
  2. 将清单应用于集群:

    kubectl apply -f web-service.yaml
    

部署 Ingress

在本部分中,您将创建一个 Ingress 资源,其可通过 Ingress 控制器触发 Compute Engine 负载均衡器的部署。适用于内部应用负载均衡器的 Ingress 需要以下注释:

annotations:
    kubernetes.io/ingress.class: "gce-internal"

您无法使用 ingressClassName 字段指定 GKE Ingress。必须使用 kubernetes.io/ingress.class 注解。如需了解详情,请参阅 GKE Ingress 控制器行为

如需创建 Ingress,请执行以下操作:

  1. 将以下示例清单保存为 internal-ingress.yaml

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ilb-demo-ingress
      namespace: default
      annotations:
        kubernetes.io/ingress.class: "gce-internal"
    spec:
      defaultBackend:
        service:
          name: hostname
          port:
            number: 80
    
  2. 将清单应用于集群:

    kubectl apply -f internal-ingress.yaml
    

验证 Ingress 部署状态是否为成功

在本部分中,您将验证部署状态是否为成功。

Ingress 资源可能需要几分钟时间才能完成预配。在此期间,Ingress 控制器会创建诸如转发规则、后端服务、网址映射和 NEG 之类的项目。

如需检索您在上一部分中创建的 Ingress 资源的状态,请运行以下命令:

kubectl get ingress ilb-demo-ingress

输出内容类似如下:

NAME               HOSTS    ADDRESS            PORTS     AGE
ilb-demo-ingress   *        10.128.0.58        80        59s

ADDRESS 字段填充后,Ingress 即已准备就绪。在此字段中使用的 RFC 1918 地址表示 VPC 中的一个内部 IP 地址。

由于内部应用负载均衡器是区域负载均衡器,因此只能从位于同一区域和 VPC 内的客户端访问虚拟 IP 地址 (VIP)。检索负载均衡器 VIP 后,您可以使用 curl 等工具从 VPC 内部对 VIP 发起 HTTP GET 调用。

如需发起 HTTP GET 调用,请完成以下步骤:

  1. 如需从 VPC 内部访问您的 Ingress VIP,请在集群所在的区域和网络中部署虚拟机:

    gcloud compute instances create l7-ilb-client \
        --image-family=debian-10 \
        --image-project=debian-cloud \
        --network=NETWORK_NAME \
        --subnet=SUBNET_NAME \
        --zone=COMPUTE_ZONE \
        --tags=allow-ssh
    

    替换以下内容:

    如需详细了解如何创建实例,请参阅创建和启动虚拟机实例

  2. 如需从虚拟机内访问内部 VIP,请使用 curl

    1. 通过 SSH 连接到您在上一步中创建的虚拟机:

      gcloud compute ssh l7-ilb-client \
          --zone=COMPUTE_ZONE
      
    2. 使用 curl 访问内部应用 VIP:

      curl 10.128.0.58
      hostname-server-6696cf5fc8-z4788
      

      如果返回成功的 HTTP 响应和一个后端容器的主机名,则表示整个负载均衡路径运行正常。

删除 Ingress 资源

移除 Ingress 和 Service 资源还会移除与其关联的 Compute Engine 负载均衡器资源。为防止资源泄露,请务必移除不再需要的 Ingress 资源。您还必须先删除 Ingress 和 Service 资源,然后才能删除集群,否则 Compute Engine 负载均衡资源将被视为孤立资源。

如需移除 Ingress,请完成以下步骤:

  1. 删除 Ingress。例如,如需删除您在此页面中创建的 Ingress,请运行以下命令:

    kubectl delete ingress ilb-demo-ingress
    

    删除 Ingress 会移除与此 Ingress 资源关联的转发规则、后端服务和网址映射。

  2. 删除 Service。例如,如需删除您在此页面中创建的 Service,请运行以下命令:

    kubectl delete service hostname
    

    删除 Service 会移除与其关联的 NEG。

如需在 GKE 上部署应用并使用专用负载均衡 IP 地址公开应用,请参阅基本内部 Ingress

静态 IP 寻址

内部 Ingress 资源同时支持静态和临时 IP 寻址。如果未指定 IP 地址,则系统会自动从 GKE 节点子网分配可用的 IP 地址。但是,Ingress 资源不会从代理专用子网预配 IP 地址,因为该子网仅供内部代理使用。这些临时 IP 地址将分配给仅适用于内部 Ingress 资源生命周期的 Ingress。如果您删除自己的 Ingress 并从同一清单文件创建新的 Ingress,则无法保证您会获取相同的外部 IP 地址。

如果您希望获取与内部 Ingress 资源生命周期无关的永久 IP 地址,则必须预留区域级静态内部 IP 地址。然后,您可以通过对 Ingress 资源使用 kubernetes.io/ingress.regional-static-ip-name 注解来指定静态 IP 地址。

以下示例展示了如何添加此注解:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.regional-static-ip-name: STATIC_IP_NAME
    kubernetes.io/ingress.class: "gce-internal"

STATIC_IP_NAME 替换为满足下列条件的静态 IP 地址名称:

  • 在部署 Ingress 之前,创建静态 IP 地址。存在静态 IP 地址之前不会部署负载均衡器,引用不存在的 IP 地址资源并不会创建静态 IP 地址。如果您修改现有 Ingress 以使用静态 IP 地址而不是临时 IP 地址,则 GKE 可能会在重新创建负载均衡器的转发规则时更改负载均衡器的 IP 地址。
  • 服务项目中为共享 VPC 的服务项目中部署的 Ingress 预留静态 IP。
  • 按名称(而非 IP 地址)引用 Google Cloud IP 地址资源。
  • 该 IP 地址必须来自 GKE 集群所在区域中的子网。您可以使用区域内的任何可用专用子网(但代理专用子网除外)。不同的 Ingress 资源也可以具有来自不同子网的地址。

客户端和负载均衡器之间的 HTTPS

适用于内部负载均衡的 Ingress 支持向客户端提供 TLS 证书。您可以通过 Kubernetes Secret 或通过 Google Cloud 中预共享的区域级 SSL 证书来提供 TLS 证书。您还可以为每个 Ingress 资源指定多个证书。 GKE 1.25 及更高版本支持同时使用 HTTPS 和 HTTP。如需启用此功能,您需要创建 PURPOSE=SHARED_LOADBALANCER_VIP 的静态 IP 地址,并在 Ingress 上配置该地址。如果未提供静态 IP 地址,则仅允许 HTTPS 流量,您需要按照停用 HTTP 的文档进行操作。

以下步骤详细介绍了如何在 Google Cloud 中创建证书,然后通过 Ingress 向内部客户端提供该证书,以用于 HTTPS 和 HTTP 流量:

  1. 创建区域级证书:

    gcloud compute ssl-certificates create CERT_NAME \
        --certificate CERT_FILE_PATH \
        --private-key KEY_FILE_PATH \
        --region COMPUTE_REGION
    

    替换以下内容:

    • CERT_NAME:您选择的证书名称。
    • CERT_FILE_PATH:用于创建自行管理的证书的本地证书文件的路径。该证书必须采用 PEM 格式。
    • KEY_FILE_PATH:本地私钥文件的路径。私钥必须采用 PEM 格式,并且必须使用 RSA 或 ECDSA 加密。
    • COMPUTE_REGION:证书的 Compute Engine 区域。
  2. 按照静态 IP 寻址预留并应用静态 IP 地址。

  3. 将以下示例清单保存为 ingress-pre-shared-cert.yaml

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ilb-demo-ing
      namespace: default
      annotations:
        ingress.gcp.kubernetes.io/pre-shared-cert: "CERT_NAME"
        kubernetes.io/ingress.regional-static-ip-name: STATIC_IP_NAME
        kubernetes.io/ingress.class: "gce-internal"
    spec:
      rules:
      - host: DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: SERVICE_NAME
                port:
                  number: 80
    

    请替换以下内容:

    • DOMAIN:您的网域。
    • CERT_NAME:您在上一部分中创建的证书的名称。
    • SERVICE_NAME:您的服务的名称。
  4. 将清单应用于集群:

    kubectl apply -f ingress-pre-shared-cert.yaml
    

负载均衡器和应用之间的 HTTPS

如果您的应用在 GKE Pod 中运行并且可以接收 HTTPS 请求,您可以将负载均衡器配置为使用 HTTPS 将请求转发给应用。如需了解详情,请参阅负载均衡器和应用之间的 HTTPS (TLS)

共享 VPC

手动添加 NEG 注解

如果要在其中部署 Ingress 资源的 GKE 位于共享 VPC 服务项目中,则系统不会自动为该服务添加注解 cloud.google.com/neg: '{"ingress": true}',因为 MutatingWebhookConfiguration 负责为尚未安装的服务注入注解。

您必须将 NEG 注解添加到通过适用于内部应用负载均衡器的 Ingress 公开的 Service 清单中。

VPC 防火墙规则

如果要在其中部署 Ingress 资源的 GKE 集群位于共享 VPC 服务项目中,并且您希望由 GKE 控制层面来管理宿主项目中的防火墙资源,则必须按照为具有共享 VPC 的集群管理防火墙资源中的要求,为该服务项目的 GKE 服务账号在宿主项目中授予适当的 IAM 权限。这样,Ingress 控制器便可创建防火墙规则,允许用于 Google Cloud 健康检查的入站流量。

以下是 Ingress 资源日志中可能存在的事件示例。如果 Ingress 控制器由于未正确配置权限而无法创建防火墙规则来允许用于 Google Cloud 健康检查的入站流量,则会发生此错误。

Firewall change required by security admin: `gcloud compute firewall-rules update <RULE_NAME> --description "GCE L7 firewall rule" --allow tcp:<PORT> --source-ranges 130.211.0.0/22,35.191.0.0/16 --target-tags <TARGET_TAG> --project <HOST_PROJECT>

如果您希望从宿主项目手动预配防火墙规则,则可以将 networking.gke.io/suppress-firewall-xpn-error: "true" 注解添加到 Ingress 资源,以忽略 firewallXPNError 事件。

内部 Ingress 注解摘要

下表显示了您在为适用于内部应用负载均衡器的 Ingress 创建 Ingress 和 Service 资源时可以添加的注解。

Ingress 注释

注解 说明
kubernetes.io/ingress.class 对于内部 Ingress,您可以设置为 "gce-internal"。如果未指定该类,则系统会默认将 Ingress 资源解释为外部 Ingress。 如需了解详情,请参阅 GKE Ingress 控制器行为
kubernetes.io/ingress.allow-http 您可以允许客户端与 HTTP(S) 负载均衡器之间的 HTTP 流量。可能的值有 truefalse。 默认值为 true。如需了解详情,请参阅停用 HTTP
ingress.gcp.kubernetes.io/pre-shared-cert 您可以将证书和密钥上传到 Google Cloud 项目。 使用此注解可以引用证书和密钥。如需了解详情,请参阅将多个 SSL 证书与外部应用负载均衡器搭配使用
networking.gke.io/suppress-firewall-xpn-error

GLBC 1.4 及更高版本中,您可以忽略 firewallXPNError 事件。对于 Ingress 负载均衡器,如果 Kubernetes 由于权限不足而无法更改防火墙规则,则会每隔几分钟创建一次 firewallXPNError 事件。

networking.gke.io/suppress-firewall-xpn-error: "true" 注解添加到 Ingress 资源。默认值为 false。您可以随时移除此注解以取消忽略。

kubernetes.io/ingress.regional-static-ip-name 您可以指定静态 IP 地址来预配内部 Ingress 资源。如需了解详情,请参阅静态 IP 寻址
注解 说明
cloud.google.com/backend-config 使用此注解配置与 servicePort 关联的后端服务。如需了解详情,请参阅 Ingress 配置
cloud.google.com/neg 使用此注释指定负载均衡器应使用网络端点组。如需了解详情,请参阅使用容器原生负载均衡

问题排查

如需了解和观察 Ingress 的状态,通常需要检查关联的资源。常见的问题类型包括负载均衡资源未正确创建、流量未到达后端或后端运行状况不佳。

一些常见问题排查步骤包括:

  • 验证客户端流量是否来自与负载均衡器相同的区域和 VPC。
  • 验证 Pod 和后端是否运行状况良好。
  • 验证 VIP 地址和 Compute Engine 健康检查的流量路径,以确保其不会被防火墙规则屏蔽。
  • 检查 Ingress 资源事件是否存在错误。
  • 描述 Ingress 资源以查看与 Compute Engine 资源的映射。
  • 验证 Compute Engine 负载均衡资源是否存在、配置是否正确且未报告错误。

过滤 Ingress 事件

以下查询会过滤集群中所有 Ingress 事件的错误:

kubectl get events --all-namespaces --field-selector involvedObject.kind=Ingress

您还可以按对象或对象名称进行过滤:

kubectl get events --field-selector involvedObject.kind=Ingress,involvedObject.name=hostname-internal-ingress

在以下错误中,您可以看到 Ingress 引用的 Service 不存在:

LAST SEEN   TYPE      REASON      OBJECT                              MESSAGE
0s          Warning   Translate   ingress/hostname-internal-ingress   error while evaluating the ingress spec: could not find service "default/hostname-invalid"

检查 Compute Engine 负载均衡器资源

以下命令会显示 Ingress 资源的完整输出,以便您可以查看由 Ingress 控制器创建的 Compute Engine 资源的映射:

kubectl get ing INGRESS_FILENAME -o yaml

INGRESS_FILENAME 替换为您的 Ingress 资源的文件名。

输出内容类似如下:

apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    annotations:
      ingress.kubernetes.io/backends: '{"k8s1-241a2b5c-default-hostname-80-29269aa5":"HEALTHY"}'
      ingress.kubernetes.io/forwarding-rule: k8s-fw-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/target-proxy: k8s-tp-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/url-map: k8s-um-default-ilb-demo-ingress--241a2b5c94b353ec
      kubectl.kubernetes.io/last-applied-configuration: |
       {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"gce-internal"},"name":"ilb-demo-ingress","namespace":"default"},"spec":{"defaultBackend":{"service":{"name":"hostname"},"port":{"number":80}}}}
      kubernetes.io/ingress.class: gce-internal
    creationTimestamp: "2019-10-15T02:16:18Z"
    finalizers:
    - networking.gke.io/ingress-finalizer
    generation: 1
    name: ilb-demo-ingress
    namespace: default
    resourceVersion: "1538072"
    selfLink: /apis/networking.k8s.io/v1/namespaces/default/ingresses/ilb-demo-ingress
    uid: 0ef024fe-6aea-4ee0-85f6-c2578f554975
  spec:
    defaultBackend:
      service:
        name: hostname
        port:
          number: 80
  status:
    loadBalancer:
      ingress:
      - ip: 10.128.0.127
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

ingress.kubernetes.io/backends 注解会列出后端及其状态。确保您的后端被列为 HEALTHY

您可以直接查询 Ingress 创建的 Compute Engine 资源,以了解其状态和配置。运行这些查询在排查问题时也会很有帮助:

如需列出所有 Compute Engine 转发规则,请使用以下命令:

gcloud compute forwarding-rules list

输出内容类似如下:

NAME                                                        REGION       IP_ADDRESS      IP_PROTOCOL  TARGET
k8s-fw-default-hostname-internal-ingress--42084f6a534c335b  REGION_NAME  10.128.15.225   TCP          REGION_NAME/targetHttpProxies/k8s-tp-default-hostname-internal-ingress--42084f6a534c335b

如需列出后端服务的运行状况,请先列出后端服务,然后复制您要检查的后端服务的名称:

gcloud compute backend-services list

输出内容类似如下:

NAME                                         BACKENDS                                                                       PROTOCOL
k8s1-42084f6a-default-hostname-80-98cbc1c1   REGION_NAME/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1 HTTP

您现在可以使用后端服务名称来查询其运行状况:

gcloud compute backend-services get-health k8s1-42084f6a-default-hostname-80-98cbc1c1 \
    --region COMPUTE_REGION

COMPUTE_REGION 替换为后端服务的 Compute Engine 区域。

输出类似于以下内容:

backend: https://www.googleapis.com/compute/v1/projects/user1-243723/zones/ZONE_NAME/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1
status:
  healthStatus:
  - healthState: HEALTHY

后续步骤