配置适用于内部 HTTP(S) 负载平衡的 Ingress

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

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

准备工作

您必须先准备网络环境,然后才能将工作负载代理部署到指定区域,然后才能通过 Kubernetes Ingress API 部署负载平衡器资源。如需了解如何部署代理专用子网,请参阅配置网络和子网

您必须先完成此步骤,然后才能部署适用于内部 HTTP(S) 负载平衡的 Ingress。

如需详细了解适用于内部 HTTP(S) 负载平衡的 Ingress 为何要求您使用代理专用子网,请参阅必需的网络环境

要求

适用于内部 HTTP(S) 负载平衡的 Ingress 具有以下要求:

  • 您的集群使用的 GKE 版本必须高于 1.16.5-gke.10。
  • 您的集群必须在 VPC 原生(别名 IP)模式下运行。如需了解详情,请参阅 VPC 原生集群
  • 您的集群必须启用 HTTP 负载平衡插件。默认情况下,集群会启用 HTTP 负载平衡。请勿停用此插件。
  • 您需要使用网络端点组 (NEG) 作为 Service 的后端。

部署适用于内部 HTTP(S) 负载平衡的 Ingress

以下练习介绍了如何部署适用于内部 HTTP(S) 负载平衡的 Ingress:

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

创建集群

在本部分中,您将创建一个集群,以便与适用于内部 HTTP(S) 负载平衡的 Ingress 配合使用。您可以使用 gcloud 命令行工具或通过 Google Cloud Console 创建此集群。

gcloud

使用以下字段创建集群:

gcloud container clusters create CLUSTER_NAME \
    --cluster-version=VERSION_NUMBER \
    --enable-ip-alias \
    --zone=ZONE \
    --network=NETWORK

请替换以下内容:

  • CLUSTER_NAME:为您的集群添加名称。
  • VERSION_NUMBER:添加高于 1.16.5-gke.10 的版本。您还可以使用 --release-channel 标志选择默认版本高于 1.16.5-gke.10 的发布版本。
  • --enable-ip-alias 表示启用别名 IP。使用适用于内部 HTTP(S) 负载平衡的 Ingress 的集群必须以“VPC 原生(别名 IP 地址)”模式运行。如需了解详情,请参阅创建 VPC 原生集群
  • ZONE:添加要在其中创建集群的可用区。您所选择的可用区必须与您在配置网络和子网时为内部 HTTP(S) 负载平衡器创建的代理子网位于同一区域。
  • NETWORK:添加要在其中创建集群的网络的名称。此网络必须与代理子网位于同一 VPC 网络中。

控制台

  1. 转到 Cloud Console 中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击 创建

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

    1. 为集群输入名称
    2. 对于位置类型,请为集群选择一个可用区。您所选择的可用区必须与您在配置网络和子网时为内部 HTTP(S) 负载平衡器创建的代理子网位于同一区域。
    3. 控制平面版本下,选择高于 1.16.5-gke.10 的静态版本,或选择默认版本高于 1.16.5-gke.10 的发布版本
  4. 在导航窗格的集群下,点击网络

    1. 网络下拉列表中,选择要在其中创建集群的网络。此网络必须与代理子网位于同一 VPC 网络中。
    2. 高级网络选项下,确保选中启用 VPC 原生流量路由(使用别名 IP 地址)启用 HTTP 负载平衡
  5. 点击创建

部署 Web 应用

在本部分中,您将创建 Deployment

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

  1. 复制以下 Deployment 资源并保存到名为 web-deployment.yaml 的文件中:

    # 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: k8s.gcr.io/serve_hostname:v1.4
            name: hostname-server
            ports:
            - containerPort: 9376
              protocol: TCP
          terminationGracePeriodSeconds: 90
    

    此 Deployment 文件使用容器映像在端口 9376 的 HTTPS 服务器上进行侦听。此 Deployment 还将为您的应用管理 Pod。每个 Pod 运行一个具有 HTTPS 服务器的应用容器,该 HTTPS 服务器会将应用服务器的主机名作为响应返回。Pod 的默认主机名就是 Pod 的名称。该容器还会处理正常终止。

  2. 创建 Deployment 文件后,您可以将该资源应用于集群:

    kubectl apply -f web-deployment.yaml
    

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

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

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

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

  • 您已在 GKE 集群 1.17.6-gke.7 及更高版本中创建了 Service。
  • 您使用的是 VPC 原生集群。
  • 您未使用共享 VPC。
  • 您未使用 GKE 网络政策

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

如果您未添加 NEG 注释,则会在 Ingress 对象上收到阻止您配置内部 HTTP(S) 负载平衡器的警告。如果未添加 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. 复制以下 Service 资源并保存到名为 web-service.yaml 的文件中:

    # 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: NodePort
    
  2. 创建 Service 文件后,您可以将该资源应用于集群:

    kubectl apply -f  web-service.yaml
    

部署 Ingress

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

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

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

  1. 复制以下 Ingress 资源并保存到名为 internal-ingress.yaml 的文件中:

    # 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. 创建 Ingress 文件后,您可以将该资源应用于集群:

    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 地址。

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

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

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

    例如,如果您已按照前面的步骤创建 Deployment、Service 和 Ingress 并且已在默认网络和 us-central1-a 可用区中创建集群,则可以使用以下命令:

    gcloud compute instances create l7-ilb-client-us-central1-a \
        --image-family=debian-9 \
        --image-project=debian-cloud \
        --network=default \
        --subnet=default \
        --zone=us-central1-a \
        --tags=allow-ssh
    

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

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

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

      gcloud compute ssh l7-ilb-client-us-central1-a \
         --zone=us-central1-a
      
    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。

静态 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 地址名称:

  • 先创建静态 IP 地址,然后再部署 Ingress。存在静态 IP 地址之前不会部署负载平衡器,引用不存在的 IP 地址资源并不会创建静态 IP 地址。
  • 服务项目中为共享 VPC 的服务项目中部署的 Ingress 预留静态 IP。
  • 按名称(而非 IP 地址)引用 Google Cloud IP 地址资源。
  • 该 IP 地址必须来自 GKE 集群所在区域中的子网。您可以使用区域内的任何可用专用子网(但代理专用子网除外)。不同的 Ingress 资源也可以具有来自不同子网的地址。

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

适用于内部负载平衡的 Ingress 支持向客户端提供 TLS 证书。您可以通过 Kubernetes Secret 或通过 Google Cloud 中预共享的区域级 SSL 证书来提供 TLS 证书。您还可以为每个 Ingress 资源指定多个证书。

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

  1. 创建区域级证书:

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

    请替换以下内容:

    • CERT_NAME:为您的证书添加名称。
    • CERT_FILE_PATH:添加本地证书文件的路径以创建自行管理的证书。该证书必须采用 PEM 格式。
    • KEY_FILE_PATH:将路径添加到本地私钥文件。私钥必须采用 PEM 格式,并且必须使用 RSA 或 ECDSA 加密。
    • REGION:为您的证书添加区域。
  2. 创建 Ingress。以下名为 ingress-pre-shared-cert.yaml 的 YAML 文件是您需要创建的 Ingress 资源示例:

    # 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.class: "gce-internal"
        kubernetes.io/ingress.allow-http: "false"
    spec:
      rules:
      - host: DOMAIN
        http:
          paths:
          - backend:
              service:
                name: SERVICE_NAME
                port:
                  number: 80
    

    请替换以下内容:

    • DOMAIN:添加您的网域。
    • CERT_NAME:添加您在上一部分中创建的证书的名称。
    • SERVICE_NAME:添加您的 Service 的名称。
  3. 创建 Ingress 后,您可以将该资源应用于集群:

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

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

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

共享 VPC

如果要在其中部署 Ingress 资源的 GKE 集群位于某个服务项目中,并且您希望由 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 注释摘要

下表显示了您在为适用于内部 HTTP(S) 负载平衡的 Ingress 创建 Ingress 和 Service 资源时可以添加的注释。

Ingress 注释

注释 说明
kubernetes.io/ingress.class 指定为内部 Ingress 的 "gce-internal"。如果未指定该类,则系统会默认将 Ingress 资源解释为外部 Ingress。
kubernetes.io/ingress.allow-http 指定是否允许客户端与 HTTP(S) 负载平衡器之间的 HTTP 流量。可能的值有 truefalse。 默认值为 true,但如果您使用 HTTPS 进行内部负载平衡,则必须将此注释设置为 false。如需了解详情,请参阅停用 HTTP
ingress.gcp.kubernetes.io/pre-shared-cert 您可以将证书和密钥上传到 Google Cloud 项目。 使用此注释可以引用证书和密钥。如需了解详情,请参阅在 HTTP(S) 负载平衡中使用多个 SSL 证书
networking.gke.io/suppress-firewall-xpn-error 对于 Ingress 负载均衡器,如果 Kubernetes 由于权限不足而无法更改防火墙规则,则系统会每隔几分钟创建一次 firewallXPNError 事件。在 GLBC 1.4 及更高版本中,您可以通过将 networking.gke.io/suppress-firewall-xpn-error: "true" 注释添加到 Ingress 资源,忽略 firewallXPNError 事件。您可以随时移除此注释以取消忽略。可能的值有 truefalse。默认值为 false
注释 说明
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  us-central1  10.128.15.225   TCP          us-central1/targetHttpProxies/k8s-tp-default-hostname-internal-ingress--42084f6a534c335b

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

gcloud compute backend-services list

输出示例:

NAME                                         BACKENDS                                                                       PROTOCOL
k8s1-42084f6a-default-hostname-80-98cbc1c1   us-central1-a/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1 HTTP

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

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

输出示例:

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

后续步骤