从边缘到网格:通过 GKE Ingress 公开服务网格应用

Last reviewed 2022-09-29 UTC

本教程介绍如何将 Anthos Service Mesh 与 Cloud Load Balancing 结合使用,以将服务网格中的应用公开给互联网客户端。

Anthos Service Mesh 是基于 Istio 的代管式服务网格,可为应用提供可观测的标准化安全增强型通信层。无论您是使用 Anthos Service Mesh、Traffic Director 还是 Istio,服务网格都可以为在网格中进行通信的客户提供全面的通信平台。但是,仍然难以将网格外部的客户端连接到网格中托管的应用。

您可以通过多种方式向客户端公开应用,具体取决于客户端所在的位置。本教程介绍了如何将 Cloud Load Balancing 与 Anthos Service Mesh 结合使用以向客户端公开应用,从而将负载均衡器与服务网格集成在一起。本教程面向运行 Anthos Service Mesh 的高级从业人员,但也适用于 Google Kubernetes Engine 上的 Istio。

网格入站流量网关

Istio 0.8 引入了网格入站流量网关,此网关提供的专用代理集的端口会向来自服务网格外部的流量公开。这些网格入站流量代理允许您独立于应用路由行为,控制 L4 公开行为。代理还允许您在网格外部流量到达应用 Sidecar 之前将路由和政策应用到网格外部流量。网格入站流量定义了流量到达网格中的节点时的处理方式,但是外部组件必须定义流量如何首先到达网格。

如需管理此外部流量,您需要一个位于网格外部的负载均衡器。本教程使用通过 GKE Ingress 资源预配的 Google Cloud Load Balancing 自动执行部署。此设置的规范示例是外部负载均衡服务,对于 Google Cloud,会部署公共 TCP/UDP 负载均衡器。该负载均衡器指向 GKE 集群的 NodePort。这些 NodePort 会公开 Istio 入站流量网关 Pod,而 Pod 会将流量路由到下游网格 Sidecar 代理。下图演示了此拓扑。内部专用流量的负载均衡类似于此架构,只是改为部署内部 TCP/UDP 负载均衡器。

外部负载均衡器通过入站流量网关代理将外部客户端路由到网格。

将 L4 透明负载均衡与网格入站网关结合使用具有以下优势:

  • 此设置简化了负载均衡器的部署过程。
  • 如果集群变更、节点中断或处理中断,则负载均衡器会提供稳定的虚拟 IP (VIP)、健康检查和可靠的流量分配。
  • 所有路由规则、TLS 终结和流量政策都会在网格入站流量网关中的同一个位置处理。

GKE Ingress 和 Service

您可以通过多种方式为集群外部的客户端提供对应用的访问权限。下表列出了可用于在 Google Cloud 上部署负载均衡器的 Kubernetes 基本组件。用于向客户端公开应用的负载均衡器的类型很大程度上取决于客户端是外部客户端还是内部客户端、需要哪种协议支持以及服务网格是跨越多个 GKE 集群还是包含在单个集群中。

下表中的任何负载均衡器类型都可以公开网格托管的应用,具体取决于使用场景。

GKE 资源 基于云的负载均衡器 特性
适用于外部 HTTP(S) 负载均衡器的 Ingress 外部 HTTP(S) 负载均衡器

Google Edge 接入点 (PoP) 中的 L7 代理

公共 VIP

全球范围

单集群

适用于内部 HTTP(S) 负载均衡器的 Ingress 内部 HTTP(S) 负载均衡器

Virtual Private Cloud (VPC) 网络中的 L7 代理

专用 VIP

地区范围

单集群

外部 LoadBalancer 服务 网络负载均衡器

Google Edge PoP 的 L4 直通

公共 VIP

地区范围

单集群

内部 LoadBalancer 服务 内部 TCP/UDP 负载均衡器

VPC 路由网络中的 L4 直通

专用 VIP

地区范围

单集群

多集群 Ingress(多集群、外部入站流量) 外部 HTTP(S) 负载均衡器

Google Edge PoP 中的 L7 代理

公共 VIP

全球范围

多集群

虽然 Anthos Service Mesh 的默认负载均衡器是外部 TCP/UDP 负载均衡器,但本教程重点介绍外部 HTTP(S) 负载均衡器。外部 HTTP(S) 负载均衡器提供与诸如 Identity-Aware Proxy (IAP)、Google Cloud Armor 和 Cloud CDN 等边缘服务以及边缘代理的全球分布式网络的集成。下一部分介绍使用两层 HTTP 负载均衡的架构和优势。

Cloud 入站流量和网格入站流量

将网格外部的 L7 负载均衡与网格入站层一起部署具有明显优势,对于互联网流量而言尤其如此。即使 Anthos Service Mesh 和 Istio 入站流量网关在网格中提供了高级路由和流量管理,某些功能仍可以在网络边缘得到更好的服务。通过 Google Cloud 的外部 HTTP(S) 负载均衡器利用互联网边缘网络,较之基于网格的入站流量,可在性能、可靠性或安全性方面获得显著的优势。这些优势如下所示:

此 L7 负载均衡的外部层称为 Cloud Ingress,因为它是以云管理的负载均衡器为基础,而不是由网格入站流量使用的自托管代理。Cloud Ingress 和网格入站流量结合,可利用 Google Cloud 基础架构和网格的互补功能。下图说明了如何将 Cloud Ingress 和网格入站流量结合,以充当互联网流量的两个负载均衡层。

Cloud Ingress 充当通过 VPC 网络到网格的外部流量的网关。

在这种拓扑中,Cloud Ingress 层从服务网格外部获取流量,并将该流量定向到网格入站流量层。然后,网格入站流量层会将流量定向到网格托管的应用后端。

Cloud 和网格入站流量拓扑

本部分介绍了每个入站流量层一起使用时可实现的互补性角色。这些角色不是具体的规则,而是利用每一层优点的指南。这种模式可能会有变体版本,具体取决于您的使用场景。

  • Cloud Ingress。与网格入站流量搭配使用时,Cloud Ingress 层最适合用于边缘安全和全球负载均衡。由于 Cloud Ingress 层在边缘与 DDoS 保护、云防火墙、身份验证和加密产品集成在一起,因此这个层擅长在网格外部运行这些服务。路由逻辑在这个层通常很简单,但是对于多集群和多地区环境而言,逻辑可能会更复杂。由于面向互联网的负载均衡器的关键功能,Cloud Ingress 层可能由基础架构团队管理,该团队对应用在互联网上的公开和保护方式具有独占控制权。较之开发者驱动的基础架构,此控制机制会降低此层的灵活性和动态性,因此如果考虑使用此控制机制,则可能会影响您要向谁提供对此层的管理员权限以及以何种方式提供。
  • 网格入站流量。与 Cloud Ingress 搭配使用时,网格入站流量层提供靠近应用的灵活路由。由于具有这种灵活性,对于复杂路由逻辑和应用级别的可见性,网格入站流量比 Cloud Ingress 更好。入站流量层之间的分隔还使应用所有者能更容易地直接控制此层,而不会影响其他团队。通过 L4 负载均衡器而不是 L7 负载均衡器公开服务网格应用时,应在网格内部的网格入站流量层终结客户端 TLS,以帮助保护应用。

健康检查

使用 L7 负载均衡的两层所带来的一种复杂性是健康检查。您必须配置每个负载均衡器以检查下一层的运行状况,确保它可以接收流量。下图中的拓扑结构显示了 Cloud Ingress 如何检查网格入站流量代理的运行状况,而网格又如何反过来检查应用后端的运行状况。

Cloud Ingress 会检查网格入站流量的运行状况,网格入站流量会检查应用后端的运行状况。

此拓扑具有以下注意事项:

  • Cloud Ingress。在本教程中,您将通过入站流量配置 Google Cloud 负载均衡器,以检查所公开健康检查端口上的网格入站流量代理的健康状况。如果网格代理关闭,或者集群、网格或地区不可用,则 Google Cloud 负载均衡器会检测此情况,并且不会将流量发送到网格代理。
  • 网格入站流量。在网格应用中,您可以直接对后端执行健康检查,以便可以在本地执行负载均衡和流量管理。

安全

上述拓扑涉及几个安全要素。最关键的要素之一是如何配置加密和部署证书。用于外部 HTTP(S) 负载均衡器的入站流量Google 管理的证书进行了深度集成。此集成可自动预配公共证书,将它们关联到负载均衡器,然后通过声明性 GKE Ingress 接口续订和轮用证书。互联网客户端根据公共证书进行身份验证,并作为 Virtual Private Cloud (VPC) 中的第一个跃点连接到外部负载均衡器。

Google Front End (GFE) 和网格入站流量代理之间的下一个跃点会默认加密。GFE 与其后端之间的网络级加密会自动应用。但是,如果您的安全要求规定平台所有者保留加密密钥的所有权,则可以在集群入站流量 (GFE) 和网格入站流量(Envoy 代理实例)之间启用具有 TLS 加密的 HTTP/2。为此路径启用具有 TLS 加密的 HTTP/2 后,您可以使用自签名证书或公共证书来加密流量,因为 GFE 不会对其进行身份验证。本指南中演示了额外的这层加密。为防止证书被错误处理,请勿在其他地方使用公共负载均衡器的公共证书。相反,我们建议您在服务网格中使用单独的证书。

如果服务网格强制执行 TLS,则将对 Sidecar 代理之间的所有流量以及网格入站流量进行加密。下图说明了从客户端到 Google Cloud 负载均衡器、从负载均衡器到网格入站流量代理以及从入站流量代理到 Sidecar 代理的 HTTPS 加密。

在网格外部使用代管式证书实现安全,而在网格内部使用内部证书实现安全。

目标

  • 在 Google Cloud 上部署 Google Kubernetes Engine (GKE) 集群。
  • 在 GKE 集群上部署基于 Istio 的 Anthos Service Mesh。
  • 配置 GKE Ingress 以终结公共 HTTPS 流量,并将该流量定向到服务网格托管的应用。
  • 在您向互联网上的客户端公开的 GKE 集群上部署 Online Boutique 应用。

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    您将通过 Cloud Shell 运行本教程中的所有终端命令。

  4. 升级到最新版本的 Google Cloud CLI:

    gcloud components update
    
  5. 设置默认的 Google Cloud 项目:

    export PROJECT=PROJECT
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT} --format="value(projectNumber)")
    gcloud config set project ${PROJECT}
    

    PROJECT 替换为您要用于本教程的项目 ID。

  6. 创建工作目录:

    mkdir -p ${HOME}/edge-to-mesh
    cd ${HOME}/edge-to-mesh
    export WORKDIR=`pwd`
    

    完成本教程后,您可以删除工作目录。

创建 GKE 集群

本教程中介绍的功能需要使用 GKE 集群 1.16 或更高版本。

  1. 在 Cloud Shell 中,创建一个新的 kubeconfig 文件。此步骤确保不会导致与现有(默认)kubeconfig 文件冲突。

    touch edge2mesh_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_kubeconfig
    
  2. 为 GKE 集群定义环境变量:

    export CLUSTER_NAME=edge-to-mesh
    export CLUSTER_LOCATION=us-west1-a
    
  3. 启用 Google Kubernetes Engine API。

    gcloud

    gcloud services enable container.googleapis.com
    

    Config Connector

    本教程包含 Config Connector 资源。您可以使用这些资源来完成与您在 gcloud 标签页中完成的相同任务。如需使用这些资源,请安装 Config Connector,然后以最适合您的环境的方式应用这些资源。

    使用以下 Services 清单:

    apiVersion: serviceusage.cnrm.cloud.google.com/v1beta1
    kind: Service
    metadata:
      annotations:
        cnrm.cloud.google.com/deletion-policy: "abandon"
        cnrm.cloud.google.com/disable-dependent-services: "false"
      name: container.googleapis.com
    spec:
      resourceID: container.googleapis.com
      projectRef:
        external: PROJECT
    
  4. 创建 GKE 集群。

    gcloud

    gcloud container clusters create ${CLUSTER_NAME} \
        --machine-type=e2-standard-4 \
        --num-nodes=4 \
        --zone ${CLUSTER_LOCATION} \
        --enable-ip-alias \
        --workload-pool=${PROJECT}.svc.id.goog \
        --release-channel rapid \
        --addons HttpLoadBalancing \
        --labels mesh_id=proj-${PROJECT_NUMBER}
    

    Config Connector

    使用以下 ContainerClusterContainerNodePool 清单:

    apiVersion: container.cnrm.cloud.google.com/v1beta1
    kind: ContainerNodePool
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
      name: edge-to-mesh
    spec:
      clusterRef:
        name: edge-to-mesh
      location: us-west1-a
      nodeConfig:
        machineType: e2-standard-4
      nodeCount: 4
    ---
    apiVersion: container.cnrm.cloud.google.com/v1beta1
    kind: ContainerCluster
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
        cnrm.cloud.google.com/remove-default-node-pool: "true"
      labels:
        mesh_id: proj-PROJECT_NUMBER
      name: edge-to-mesh
    spec:
      addonsConfig:
        httpLoadBalancing:
          disabled: false
      location: us-west1-a
      initialNodeCount: 1
      releaseChannel:
        channel: RAPID
      workloadIdentityConfig:
        workloadPool: PROJECT.svc.id.goog
    

    PROJECT_NUMBER 替换为之前检索到的 PROJECT_NUMBER 环境变量的值。

    如需使用云入站流量,您必须启用 HTTP 负载均衡插件。GKE 集群默认启用了 HTTP 负载均衡;您不得将其停用。

    如需使用代管式 Anthos Service Mesh,您必须在集群上应用 mesh_id 标签。

  5. 确保该集群正在运行:

    gcloud container clusters list
    

    输出内容类似如下:

    NAME          LOCATION    MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    edge-to-mesh  us-west1-a  v1.22.6-gke.300   35.233.195.59  e2-standard-4  v1.22.6-gke.300   4          RUNNING
    
  6. 连接到该集群:

    gcloud container clusters get-credentials ${CLUSTER_NAME} \
        --zone ${CLUSTER_LOCATION} \
        --project ${PROJECT}
    

安装服务网格

在本部分中,您将配置使用队列 API 的代管式 Anthos Service Mesh

  1. 启用必需的 API:

    gcloud

    gcloud services enable mesh.googleapis.com
    

    Config Connector

    使用以下 Services 清单:

    apiVersion: serviceusage.cnrm.cloud.google.com/v1beta1
    kind: Service
    metadata:
      annotations:
        cnrm.cloud.google.com/deletion-policy: "abandon"
        cnrm.cloud.google.com/disable-dependent-services: "false"
      name: mesh.googleapis.com
    spec:
      resourceID: mesh.googleapis.com
      projectRef:
        external: PROJECT
    
  2. 在舰队上启用 Anthos Service Mesh:

    gcloud

    gcloud container fleet mesh enable
    

    Config Connector

    使用以下 GKEHubFeature 清单:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubFeature
    metadata:
      name: servicemesh
    spec:
      projectRef:
        external: PROJECT
      location: global
      resourceID: servicemesh
    
  3. 将集群注册到舰队:

    gcloud

    gcloud container fleet memberships register ${CLUSTER_NAME} \
        --gke-cluster ${CLUSTER_LOCATION}/${CLUSTER_NAME} \
        --enable-workload-identity
    

    Config Connector

    使用以下 GKEHubMembership 清单:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubMembership
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT
      name: edge-to-mesh
    spec:
      location: global
      authority:
        issuer: https://container.googleapis.com/v1/projects/PROJECT/locations/us-west1-a/clusters/edge-to-mesh
      endpoint:
        gkeCluster:
          resourceRef:
            name: edge-to-mesh
    
  4. 启用自动控制平面管理和代管式数据平面:

    gcloud

    gcloud container fleet mesh update \
        --management automatic \
        --memberships ${CLUSTER_NAME}
    

    Config Connector

    使用以下 GKEHubFeatureMembership 清单:

    apiVersion: gkehub.cnrm.cloud.google.com/v1beta1
    kind: GKEHubFeatureMembership
    metadata:
      name: servicemesh-membership
    spec:
      projectRef:
        external: PROJECT_ID
      location: global
      membershipRef:
        name: edge-to-mesh
      featureRef:
        name: servicemesh
      mesh:
        management: MANAGEMENT_AUTOMATIC
    
  5. 几分钟后,验证控制平面状态是否为 ACTIVE

    gcloud container fleet mesh describe
    

    输出内容类似如下:

    ...
    membershipSpecs:
      projects/841956571429/locations/global/memberships/edge-to-mesh:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/841956571429/locations/global/memberships/edge-to-mesh:
        servicemesh:
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision(s) ready for use: asm-managed-rapid.'
          updateTime: '2022-09-29T05:30:28.320896186Z'
    name: projects/your-project/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    ...
    

部署 GKE Ingress

在以下步骤中,您将通过 GKE 的 Ingress 控制器部署外部 HTTP(S) 负载均衡器。Ingress 资源会自动执行负载均衡器、负载均衡器 TLS 证书以及后端健康检查的预配。此外,您还可以使用 Cloud Endpoints 自动为应用预配公共 DNS 名称。

安装入站流量网关

为保证安全性,我们建议在与控制层面不同的命名空间中部署入站流量网关。

  1. 在 Cloud Shell 中,创建一个专用的 asm-ingress 命名空间:

    kubectl create namespace asm-ingress
    
  2. 将命名空间标签添加到 asm-ingress 命名空间:

    kubectl label namespace asm-ingress istio-injection=enabled
    

    输出内容类似如下:

    namespace/asm-ingress labeled
    

    使用 istio-injection=enabledasm-ingress 命名空间添加标签会指示 Anthos Service Mesh 在部署应用时自动注入 Envoy 边车代理。

  3. 运行以下命令,将 Deployment 清单创建为 ingress-deployment.yaml

    cat <<EOF > ingress-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        matchLabels:
          asm: ingressgateway
      template:
        metadata:
          annotations:
            # This is required to tell Anthos Service Mesh to inject the gateway with the
            # required configuration.
            inject.istio.io/templates: gateway
          labels:
            asm: ingressgateway
        spec:
          securityContext:
            fsGroup: 1337
            runAsGroup: 1337
            runAsNonRoot: true
            runAsUser: 1337
          containers:
          - name: istio-proxy
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                - all
              privileged: false
              readOnlyRootFilesystem: true
            image: auto # The image will automatically update each time the pod starts.
            resources:
              limits:
                cpu: 2000m
                memory: 1024Mi
              requests:
                cpu: 100m
                memory: 128Mi
          serviceAccountName: asm-ingressgateway
    ---
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      maxReplicas: 5
      minReplicas: 3
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: asm-ingressgateway
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    EOF
    

    Deployment 具有自己的 ServiceAccount 以及关联的 RoleRoleBinding,允许网关访问证书。

  4. 在集群中部署 ingress-deployment.yaml 以创建 Deployment 资源:

    kubectl apply -f ingress-deployment.yaml
    

    输出内容类似如下:

    deployment.apps/asm-ingressgateway configured
    role.rbac.authorization.k8s.io/asm-ingressgateway configured
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway configured
    serviceaccount/asm-ingressgateway created
    

    确保所有部署都已启动并运行:

    kubectl wait --for=condition=available --timeout=600s deployment --all -n asm-ingress
    

    输出内容类似如下:

    deployment.apps/asm-ingressgateway condition met
    
  5. 运行以下命令,将 Service 清单创建为 ingress-service.yaml

    cat <<EOF > ingress-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
        cloud.google.com/backend-config: '{"default": "ingress-backendconfig"}'
        cloud.google.com/app-protocols: '{"https":"HTTP2"}' # HTTP/2 with TLS encryption
      labels:
        asm: ingressgateway
    spec:
      ports:
      # status-port exposes a /healthz/ready endpoint that can be used with GKE Ingress health checks
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      # Any ports exposed in Gateway resources should be exposed here.
      - name: http2
        port: 80
        targetPort: 8080
      - name: https
        port: 443
        targetPort: 8443
      selector:
        asm: ingressgateway
      type: ClusterIP
    EOF
    

    Service 具有以下注释,可在部署 Ingress 负载均衡器时设置其参数:

    • cloud.google.com/backend-config 是指名为 BackendConfig 的自定义资源的名称。Ingress 控制器使用 BackendConfig 设置 Google Cloud BackendService 资源的参数。您可以在下一步中使用此资源来定义 Google Cloud 健康检查的自定义参数。
    • cloud.google.com/neg: '{"ingress": true}' 用于启用容器原生负载均衡的 Ingress 后端(本例中为网格入站流量代理)。为了更有效、更稳定地实现负载均衡,这些后端使用网络端点组 (NEG) 代替实例组。
    • 为了获得额外加密层,cloud.google.com/app-protocols: '{"https":"HTTP2"}' 指示 GFE 使用具有 TLS 的 HTTP2 连接到服务网格的入站网关,如适用于外部 HTTP(S) 负载均衡的 Ingress外部 HTTP(S) 负载均衡概览所述。
  6. 在集群中部署 ingress-service.yaml 以创建 Service 资源:

    kubectl apply -f ingress-service.yaml
    

    输出内容类似如下:

    service/asm-ingressgateway created
    

应用后端服务设置

  1. 在 Cloud Shell 中,运行以下命令以将 BackendConfig 清单创建为 ingress-backendconfig.yaml

    cat <<EOF > ingress-backendconfig.yaml
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: ingress-backendconfig
      namespace: asm-ingress
    spec:
      healthCheck:
        requestPath: /healthz/ready
        port: 15021
        type: HTTP
      securityPolicy:
        name: edge-fw-policy
    EOF
    

    BackendConfig 是自定义资源定义 (CRD),用于定义 Ingress 负载均衡的后端参数。如需查看可通过 GKE Ingress 配置的后端和前端参数的完整列表,请参阅 Ingress 功能

    在本教程中,BackendConfig 清单指定网格入站流量代理的自定义健康检查。Anthos Service Mesh 和 Istio 在 /healthz/ready 路径的端口 15021 上公开 Sidecar 代理健康检查自定义健康检查参数是必需的,因为网格入站流量代理的服务端口 (443) 与健康检查端口 (15021) 不同。GKE Ingress 在 BackendConfig 中使用以下健康检查参数来配置 Google Cloud 负载均衡器健康检查。此外,还引用了安全政策,以帮助防范来自不同类型的网络攻击的负载均衡流量。

    • healthCheck.port 会定义端口,以在每个 Pod 的 IP 地址上接收 Google Cloud 负载均衡器执行的健康检查。
    • healthCheck.requestPath 会定义 HTTP 路径,以在指定端口上接收健康检查。
    • type 会定义健康检查的协议(在此示例中为 HTTP)。
    • securityPolicy.name 是指 Cloud Armor 安全政策的名称。
  2. 在集群中部署 ingress-backendconfig.yaml 以创建 BackendConfig 资源:

    kubectl apply -f ingress-backendconfig.yaml
    

    输出内容类似如下:

    backendconfig.cloud.google.com/ingress-backendconfig created
    

    在部署 Ingress 资源之前,BackendConfig 参数和 asm-ingressgateway Service 注释不会应用于 Google Cloud 负载均衡器。Ingress 部署会将所有这些资源相关联。

定义安全政策

Google Cloud Armor 提供的 DDoS 防御和可自定义的安全策略可通过 Ingress 资源关联至负载均衡器。在以下步骤中,您将创建安全政策,以使用预配置规则来阻止跨站脚本攻击 (XSS)。此规则有助于阻止与已知攻击签名匹配的流量,但允许所有其他流量。您的环境可能根据工作负载使用不同的规则。

gcloud

  1. 在 Cloud Shell 中,创建一个名为 edge-fw-policy 的安全政策:

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. 创建使用预配置 XSS 过滤条件的安全政策规则:

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    

Config Connector

使用以下 ComputeSecurityPolicy 清单:

apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeSecurityPolicy
metadata:
  annotations:
    cnrm.cloud.google.com/project-id: PROJECT_ID
  name: edge-fw-policy
spec:
  rule:
  - action: allow
    description: "Default rule"
    match:
      versionedExpr: SRC_IPS_V1
      config:
        srcIpRanges:
        - "*"
    priority: 2147483647
  - action: deny-403
    description: "XSS attack filtering"
    match:
      expr:
        expression: "evaluatePreconfiguredExpr('xss-stable')"
    priority: 1000

上一部分中的 ingress-backendconfig 引用了 edge-fw-policy。部署 Ingress 资源后,它会将此安全政策与负载均衡器绑定,以帮助保护 asm-ingressgateway Service 的任何后端。

配置 IP 寻址和 DNS

  1. 在 Cloud Shell 中,为 Google Cloud 负载均衡器创建全球静态 IP:

    gcloud

    gcloud compute addresses create ingress-ip --global
    

    Config Connector

    使用以下 ComputeAddress 清单:

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      annotations:
        cnrm.cloud.google.com/project-id: PROJECT_ID
      name: ingress-ip
    spec:
      location: global
    

    此静态 IP 由 Ingress 资源使用,即使外部负载均衡器发生更改,该 IP 也可以保持不变。

  2. 获取静态 IP 地址:

    export GCLB_IP=$(gcloud compute addresses describe ingress-ip --global --format "value(address)")
    echo ${GCLB_IP}
    

    如需针对您的 Ingress IP 创建易于使用的稳定映射,您必须具有公共 DNS 记录。您可以使用所需的任何 DNS 提供商和自动化功能。本教程使用 Endpoints 而不是创建代管式 DNS 区域。Endpoints 为公共 IP 提供免费的 Google 管理的 DNS 记录

  3. 运行以下命令以创建名为 dns-spec.yaml 的 YAML 规范文件:

    cat <<EOF > dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.${PROJECT}.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.${PROJECT}.cloud.goog"
      target: "${GCLB_IP}"
    EOF
    

    YAML 规范以 frontend.endpoints.${PROJECT}.cloud.goog 的形式定义公共 DNS 记录,其中 ${PROJECT} 是您的唯一项目编号。

  4. 在 Google Cloud 项目中部署 dns-spec.yaml 文件:

    gcloud endpoints services deploy dns-spec.yaml
    

    输出内容类似如下:

    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/rollouts.frontend.endpoints.edge2mesh.cloud.goog:442b2b38-4aee-4c60-b9fc-28731657ee08
    
    Service Configuration [2021-11-14r0] uploaded for service [frontend.endpoints.edge2mesh.cloud.goog]
    

    在配置 IP 和 DNS 后,您可以生成公共证书来保护 Ingress 前端。GKE Ingress 支持 Google 管理的证书作为 Kubernetes 资源,让您能够通过声明方式预配证书。

预配 TLS 证书

  1. 在 Cloud Shell 中,运行以下命令以将 ManagedCertificate 清单创建为 managed-cert.yaml

    cat <<EOF > managed-cert.yaml
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: gke-ingress-cert
      namespace: asm-ingress
    spec:
      domains:
        - "frontend.endpoints.${PROJECT}.cloud.goog"
    EOF
    

    此 YAML 文件指定使用通过 Endpoints 创建的 DNS 名称来预配公共证书。由于 Google 全面管理这些公共证书的生命周期,因此这些证书会定期自动生成并轮用,用户无需直接干预。

  2. 在您的 GKE 集群中部署 managed-cert.yaml 文件:

    kubectl apply -f managed-cert.yaml
    

    输出内容类似如下:

    managedcertificate.networking.gke.io/gke-ingress-cert created
    
  3. 检查 ManagedCertificate 资源以查看证书生成进度:

    kubectl describe managedcertificate gke-ingress-cert -n asm-ingress
    

    输出内容类似如下:

    Name:         gke-ingress-cert
    Namespace:    asm-ingress
    Labels:       <none>
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"networking.gke.io/v1","kind":"ManagedCertificate","metadata":{"annotations":{},"name":"gke-ingress-cert","namespace":"...
    API Version:  networking.gke.io/v1
    Kind:         ManagedCertificate
    Metadata:
      Creation Timestamp:  2020-08-05T20:44:49Z
      Generation:          2
      Resource Version:    1389781
      Self Link:           /apis/networking.gke.io/v1/namespaces/asm-ingress/managedcertificates/gke-ingress-cert
      UID:                 d74ec346-ced9-47a8-988a-6e6e9ddc4019
    Spec:
      Domains:
        frontend.endpoints.edge2mesh.cloud.goog
    Status:
      Certificate Name:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      Certificate Status:  Provisioning
      Domain Status:
        Domain:  frontend.endpoints.edge2mesh.cloud.goog
        Status:  Provisioning
    Events:
      Type    Reason  Age   From                            Message
      ----    ------  ----  ----                            -------
      Normal  Create  44s   managed-certificate-controller  Create SslCertificate mcrt-306c779e-8439-408a-9634-163664ca6ced
    

    证书准备就绪后,Certificate StatusActive

部署 Ingress 资源

  1. 在 Cloud Shell 中,运行以下命令以将 Ingress 清单创建为 ingress.yaml

    cat <<EOF > ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gke-ingress
      namespace: asm-ingress
      annotations:
        kubernetes.io/ingress.allow-http: "false"
        kubernetes.io/ingress.global-static-ip-name: "ingress-ip"
        networking.gke.io/managed-certificates: "gke-ingress-cert"
        kubernetes.io/ingress.class: "gce"
    spec:
      defaultBackend:
        service:
          name: asm-ingressgateway
          port:
            number: 443
      rules:
      - http:
          paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: asm-ingressgateway
                port:
                  number: 443
    EOF
    

    此清单定义了一个将所有先前资源关联在一起的 Ingress 资源。清单指定了以下字段:

    • kubernetes.io/ingress.allow-http: "false" 会停用 Google Cloud 负载均衡器的端口 80 上的 HTTP 流量。由于端口 443 仅侦听 HTTPS,而且端口 80 已停用,因此这可以有效地防止任何客户端使用未加密的流量进行连接。
    • kubernetes.io/ingress.global-static-ip-name: "ingress-ip" 会将先前创建的 IP 地址与负载均衡器相关联。通过此链接,您可以将 IP 地址与负载均衡器分开创建,以便可以在负载均衡器生命周期中重复使用该地址。
    • networking.gke.io/managed-certificates: "gke-ingress-cert" 会将此负载均衡器与以前创建的 Google 管理的 SSL 证书资源相关联。
  2. 在您的集群中部署 ingress.yaml

    kubectl apply -f ingress.yaml
    
  3. 检查 Ingress 资源,以检查负载均衡器部署的进度:

    kubectl describe ingress gke-ingress -n asm-ingress
    

    输出内容类似如下:

    ...
    Annotations:
      ingress.kubernetes.io/https-forwarding-rule:       k8s2-fs-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/ssl-cert:                    mcrt-306c779e-8439-408a-9634-163664ca6ced
      networking.gke.io/managed-certificates:            gke-ingress-cert
      kubernetes.io/ingress.global-static-ip-name:  ingress-ip
      ingress.gcp.kubernetes.io/pre-shared-cert:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      ingress.kubernetes.io/backends:               {"k8s-be-31610--07bdde06b914144a":"HEALTHY","k8s1-07bdde06-asm-ingress-asm-ingressgateway-443-228c1881":"HEALTHY"}
      ingress.kubernetes.io/forwarding-rule:        k8s2-fr-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/https-target-proxy:     k8s2-ts-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/target-proxy:           k8s2-tp-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/url-map:                k8s2-um-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
    ...
    

    如果 ingress.kubernetes.io/backends 注释指明后端为 HEALTHY,则表示 Ingress 资源已准备就绪。这些注释还会显示已预配的不同 Google Cloud 资源的名称,包括后端服务、SSL 证书和 HTTPS 目标代理。

安装自签名入站流量网关证书

在以下步骤中,您将生成并安装一个证书(作为 Kubernetes secret 资源),使 GFE 能够建立与服务网格入站流量网关的 TLS 连接。如需更详细地了解入站流量网关证书的要求,请参阅安全后端协议注意事项指南

  1. 在 Cloud Shell 中,使用 openssl 创建私钥和证书:

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.${PROJECT}.cloud.goog/O=Edge2Mesh Inc" \
     -keyout frontend.endpoints.${PROJECT}.cloud.goog.key \
     -out frontend.endpoints.${PROJECT}.cloud.goog.crt
    
  2. asm-ingress 命名空间中创建 Secret

    kubectl -n asm-ingress create secret tls edge2mesh-credential \
     --key=frontend.endpoints.${PROJECT}.cloud.goog.key \
     --cert=frontend.endpoints.${PROJECT}.cloud.goog.crt
    

配置适用于外部负载均衡的入站流量网关

在以下步骤中,您将在 asm-ingress 命名空间中创建共享 Gateway 资源。网关通常由平台管理员或网络管理员团队负责运行。因此,Gateway 资源在由平台管理员负责管理的 asm-ingress 命名空间中创建,可通过他们自己的 VirtualService 条目在其他命名空间中使用。

  1. 在 Cloud Shell 中,运行以下命令以将 Gateway 清单创建为 ingress-gateway.yaml

    cat <<EOF > ingress-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, see note below
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    

    请注意,您必须在 Gatewayhosts 字段中使用通配符 * 条目。GCLB 不使用后端的 SNI 扩展程序。使用通配符条目会将加密的数据包(从 GCLB)发送到 ASM 入站流量网关。ASM 入站流量网关解密数据包,并使用 HTTP 主机标头(在解密的数据包中)做出路由决策(基于 VirtualService 条目)。

  2. 在您的集群中部署 ingress-gateway.yaml

    kubectl apply -f ingress-gateway.yaml
    

    输出内容类似如下:

    gateway.networking.istio.io/asm-ingressgateway created
    

安装 Online Boutique 示例应用

  1. 在 Cloud Shell 中,创建一个专用的 onlineboutique 命名空间:

    kubectl create namespace onlineboutique
    
  2. 将命名空间标签添加到 onlineboutique 命名空间:

    kubectl label namespace onlineboutique istio-injection=enabled
    

    输出内容类似如下:

    namespace/onlineboutique labeled
    

    使用 istio-injection=enabledonlineboutique 命名空间添加标签会指示 Anthos Service Mesh 在部署应用时自动注入 Envoy 边车代理。

  3. 下载 Online Boutique 示例应用的 Kubernetes YAML 文件:

    curl -LO \
        https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/release/kubernetes-manifests.yaml
    
  4. 部署 Online Boutique 应用:

    kubectl apply -f kubernetes-manifests.yaml -n onlineboutique
    

    输出内容类似如下:

    deployment.apps/frontend created
    service/frontend created
    service/frontend-external created
    ...
    
  5. 确保所有部署都已启动并运行:

    kubectl get pods -n onlineboutique
    

    输出内容类似如下:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-d854d8786-fjb7q                2/2     Running   0          3m
    cartservice-85b5d5b4ff-8qn7g             2/2     Running   0          2m59s
    checkoutservice-5f9bf659b8-sxhsq         2/2     Running   0          3m1s
    ...
    
  6. 运行以下命令,将 VirtualService 清单创建为 frontend-virtualservice.yaml

    cat <<EOF > frontend-virtualservice.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend-ingress
      namespace: onlineboutique
    spec:
      hosts:
      - "frontend.endpoints.${PROJECT}.cloud.goog"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    

    请注意,VirtualService 是在应用命名空间 (onlineboutique) 中创建的。通常,应用所有者会决定并配置将流量路由到 frontend 应用的方式和内容,以便应用所有者部署 VirtualService

  7. 在您的集群中部署 frontend-virtualservice.yaml

    kubectl apply -f frontend-virtualservice.yaml
    

    输出内容类似如下:

    virtualservice.networking.istio.io/frontend-virtualservice created
    
  8. 访问以下链接:

    echo "https://frontend.endpoints.${PROJECT}.cloud.goog"
    

    系统会显示您的 Online Boutique 前端。

    Online Boutique 首页上显示的商品。

  9. 如需显示证书的详情,请在浏览器的地址栏中点击 查看站点信息,然后点击证书(有效)

    证书查看器会显示代管证书的详情,包括到期日期和颁发证书的人。

现在,您有一个全球 HTTPS 负载均衡器,作为服务网格托管应用的前端。

清理

完成本教程后,您可以清理您在 Google Cloud 上创建的资源,以免这些资源将来产生费用。您可以彻底删除项目,也可以删除集群资源,然后删除集群。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

逐个删除资源

如果您希望保留在本教程中使用的 Google Cloud 项目,请删除单个资源:

  1. 删除 Ingress 资源:

    kubectl delete -f ingress.yaml
    
  2. 删除代管式证书:

    kubectl delete -f managed-cert.yaml
    
  3. 删除 Endpoints DNS 条目:

    gcloud endpoints services delete "frontend.endpoints.${PROJECT}.cloud.goog"
    

    输出内容类似如下:

    Are you sure? This will set the service configuration to be deleted, along
    with all of the associated consumer information. Note: This does not
    immediately delete the service configuration or data and can be undone using
    the undelete command for 30 days. Only after 30 days will the service be
    purged from the system.
    
  4. 当系统提示您继续时,请输入 Y

    输出内容类似如下:

    Waiting for async operation operations/services.frontend.endpoints.edge2mesh.cloud.goog-5 to complete...
    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/services.frontend.endpoints.edge2mesh.cloud.goog-5
    
  5. 删除静态 IP 地址:

    gcloud compute addresses delete ingress-ip --global
    

    输出内容类似如下:

    The following global addresses will be deleted:
    
     - [ingress-ip]
    
  6. 当系统提示您继续时,请输入 Y

    输出内容类似如下:

    Deleted
    [https://www.googleapis.com/compute/v1/projects/edge2mesh/global/addresses/ingress-ip].
    
  7. 删除 GKE 集群:

    gcloud container clusters delete $CLUSTER_NAME --zone $CLUSTER_LOCATION
    

后续步骤