Da borda à malha de vários clusters: implantar aplicativos distribuídos globalmente com o gateway do GKE e o Cloud Service Mesh

Last reviewed 2024-06-30 UTC

Este documento mostra como realizar as seguintes tarefas:

Este guia de implantação é destinado a administradores de plataforma. Ele também é destinado a profissionais avançados que executam o Cloud Service Mesh. As instruções também funcionam para o Istio no GKE.

Arquitetura

O diagrama a seguir mostra a topologia de entrada padrão de uma malha de serviços: um balanceador de carga TCP/UDP externo que expõe os proxies do gateway de entrada em um cluster único:

Um balanceador de carga externo encaminha os clientes externos para a malha por meio de proxies de gateway de entrada.

Este guia de implantação usa recursos do gateway do Google Kubernetes Engine (GKE). Especificamente, ele usa um gateway de vários clusters para configurar o balanceamento de carga em várias regiões na frente de vários clusters do Autopilot distribuídos em duas regiões.

Criptografia TLS do cliente, de um balanceador de carga e da malha.

O diagrama anterior mostra como os dados fluem pelos cenários de entrada de nuvem e entrada de malha. Para mais informações, consulte a explicação do diagrama de arquitetura no documento de arquitetura de referência associado.

Objetivos

  • Implante um par de clusters do GKE Autopilot no Google Cloud na mesma frota.
  • Implante uma malha de serviço do Cloud baseada no Istio na mesma frota.
  • Configure um balanceador de carga usando o gateway do GKE para encerrar o tráfego HTTPS público.
  • Direcione o tráfego HTTPS público para aplicativos hospedados pelo Cloud Service Mesh implantados em vários clusters e regiões.
  • Implante o aplicativo de exemplo whereami nos dois clusters do Autopilot.

Otimização de custos

Neste documento, você vai usar os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na sua projeção de uso, utilize a calculadora de preços.

Novos usuários do Google Cloud podem estar qualificados para um teste sem custo financeiro.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Para mais informações, consulte Limpeza.

Antes de começar

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    Todos os comandos de terminal desta implantação são executados a partir do Cloud Shell.

  4. Defina seu projeto Google Cloud padrão:

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

    Substitua PROJECT_ID pelo ID do projeto que você quer usar nesta implantação.

  5. Crie um diretório de trabalho:

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    
  6. Criar clusters do GKE

    Nesta seção, você cria clusters do GKE para hospedar os aplicativos e a infraestrutura de suporte, que serão criados mais adiante neste guia de implantação.

    1. No Cloud Shell, crie um novo arquivo kubeconfig. Esta etapa garante que você não crie conflitos com seu arquivo kubeconfig (padrão) atual.

      touch edge2mesh_mr_kubeconfig
      export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
      
    2. Defina as variáveis de ambiente usadas ao criar os clusters do GKE e os recursos neles. Modifique as opções de região padrão de acordo com seus objetivos.

      export CLUSTER_1_NAME=edge-to-mesh-01
      export CLUSTER_2_NAME=edge-to-mesh-02
      export CLUSTER_1_REGION=us-central1
      export CLUSTER_2_REGION=us-east4
      export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
      
    3. Ative as APIs do Google Cloud usadas neste guia:

      gcloud services enable \
        container.googleapis.com \
        mesh.googleapis.com \
        gkehub.googleapis.com \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        certificatemanager.googleapis.com
      
    4. Crie um cluster do GKE Autopilot com nós particulares em CLUSTER_1_REGION. Use a flag --async para evitar a espera pelo provisionamento e registro do primeiro cluster na frota:

      gcloud container clusters create-auto --async \
      ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \
      --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
      --enable-private-nodes --enable-fleet
      
    5. Crie e registre um segundo cluster do Autopilot em CLUSTER_2_REGION:

      gcloud container clusters create-auto \
      ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \
      --release-channel rapid --labels mesh_id=proj-${PROJECT_NUMBER} \
      --enable-private-nodes --enable-fleet
      
    6. Verifique se os clusters estão sendo executados. Pode levar até 20 minutos até que todos os clusters estejam em execução:

      gcloud container clusters list
      

      O resultado será assim:

      NAME             LOCATION     MASTER_VERSION  MASTER_IP       MACHINE_TYPE  NODE_VERSION    NUM_NODES  STATUS
      edge-to-mesh-01  us-central1  1.27.5-gke.200  34.27.171.241   e2-small      1.27.5-gke.200             RUNNING
      edge-to-mesh-02  us-east4     1.27.5-gke.200  35.236.204.156  e2-small      1.27.5-gke.200             RUNNING
      
    7. Colete as credenciais para CLUSTER_1_NAME. Você criou CLUSTER_1_NAME de forma assíncrona para executar outros comandos enquanto o cluster estava provisionado.

      gcloud container clusters get-credentials ${CLUSTER_1_NAME} \
          --region ${CLUSTER_1_REGION}
      
    8. Para esclarecer os nomes dos contextos do Kubernetes, renomeie-os para os nomes dos clusters:

      kubectl config rename-context gke_PROJECT_ID_${CLUSTER_1_REGION}_${CLUSTER_1_NAME} ${CLUSTER_1_NAME}
      kubectl config rename-context gke_PROJECT_ID_${CLUSTER_2_REGION}_${CLUSTER_2_NAME} ${CLUSTER_2_NAME}
      

    Instalar uma malha de serviço

    Nesta seção, você configurará o Cloud Service Mesh gerenciado com a API Fleet. O uso da API Fleet para ativar o Cloud Service Mesh oferece uma abordagem declarativa para provisionar uma malha de serviço.

    1. No Cloud Shell, ative o Cloud Service Mesh na frota:

      gcloud container fleet mesh enable
      
    2. Ative o gerenciamento automático do plano de controle e do plano de dados:

      gcloud container fleet mesh update \
        --management automatic \
        --memberships ${CLUSTER_1_NAME},${CLUSTER_2_NAME}
      
    3. Espere aproximadamente 20 minutos. Em seguida, verifique se o status do plano de controle é ACTIVE:

      gcloud container fleet mesh describe
      

      O resultado será assim:

      createTime: '2023-11-30T19:23:21.713028916Z'
      membershipSpecs:
        projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
          mesh:
            management: MANAGEMENT_AUTOMATIC
        projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
          mesh:
            management: MANAGEMENT_AUTOMATIC
      membershipStates:
        projects/603904278888/locations/us-central1/memberships/edge-to-mesh-01:
          servicemesh:
            controlPlaneManagement:
              details:
              - code: REVISION_READY
                details: 'Ready: asm-managed-rapid'
              implementation: ISTIOD
              state: ACTIVE
            dataPlaneManagement:
              details:
              - code: OK
                details: Service is running.
              state: ACTIVE
          state:
           code: OK
            description: |-
              Revision ready for use: asm-managed-rapid.
              All Canonical Services have been reconciled successfully.
            updateTime: '2024-06-27T09:00:21.333579005Z'
        projects/603904278888/locations/us-east4/memberships/edge-to-mesh-02:
          servicemesh:
            controlPlaneManagement:
              details:
              - code: REVISION_READY
                details: 'Ready: asm-managed-rapid'
              implementation: ISTIOD
              state: ACTIVE
            dataPlaneManagement:
              details:
              - code: OK
                details: Service is running.
              state: ACTIVE
          state:
            code: OK
            description: |-
              Revision ready for use: asm-managed-rapid.
              All Canonical Services have been reconciled successfully.
            updateTime: '2024-06-27T09:00:24.674852751Z'
      name: projects/e2m-private-test-01/locations/global/features/servicemesh
      resourceState:
        state: ACTIVE
      spec: {}
      updateTime: '2024-06-04T17:16:28.730429993Z'
      

    Implantar um balanceador de carga de aplicativo externo e criar gateways de entrada

    Nesta seção, você implanta um balanceador de carga de aplicativo externo pelo GKE Gateway Controller e cria gateways de entrada para os dois clusters. Os recursos gateway e gatewayClass automatizam o provisionamento do balanceador de carga e da verificação de integridade do back-end. Para fornecer terminação TLS no balanceador de carga, crie recursos do Gerenciador de certificados e anexe-os ao balanceador de carga. Além disso, use os Endpoints para provisionar automaticamente um nome DNS público ao aplicativo.

    Instalar um gateway de entrada nos dois clusters

    Como prática recomendada de segurança, recomendamos que você implante o gateway de entrada em um namespace diferente do plano de controle de malha.

    1. No Cloud Shell, crie um namespace asm-ingress dedicado em cada cluster:

      kubectl --context=${CLUSTER_1_NAME} create namespace asm-ingress
      kubectl --context=${CLUSTER_2_NAME} create namespace asm-ingress
      
    2. Adicione um rótulo ao namespace asm-ingress:

      kubectl --context=${CLUSTER_1_NAME} label namespace asm-ingress istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} label namespace asm-ingress istio-injection=enabled
      

      O resultado será assim:

      namespace/asm-ingress labeled
      

      Rotular os namespaces asm-ingress com istio-injection=enabled instrui o Cloud Service Mesh a injetar automaticamente os proxies sidecar do Envoy quando um pod é implantado.

    3. Gere um certificado autoassinado para uso futuro:

      openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
       -subj "/CN=frontend.endpoints.PROJECT_ID.cloud.goog/O=Edge2Mesh Inc" \
       -keyout ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       -out ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      

      O certificado oferece uma camada adicional de criptografia entre o balanceador de carga e os gateways de entrada da malha de serviço. Ele também é compatível com protocolos baseados em HTTP/2, como o gRPC. As instruções sobre como anexar o certificado autoassinado aos gateways de entrada serão fornecidas mais adiante em Criar recursos de endereço IP externo, registro DNS e certificado TLS.

      Para mais informações sobre os requisitos do certificado do gateway de entrada, consulte Criptografia do balanceador de carga para os back-ends.

    4. Crie um secret do Kubernetes em cada cluster para armazenar o certificado autoassinado:

      kubectl --context ${CLUSTER_1_NAME} -n asm-ingress create secret tls \
       edge2mesh-credential \
       --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      kubectl --context ${CLUSTER_2_NAME} -n asm-ingress create secret tls \
       edge2mesh-credential \
       --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
       --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
      
    5. Para integrar com o balanceador de carga de aplicativo externo, crie uma variante kustomize para configurar os recursos do gateway de entrada:

      mkdir -p ${WORKDIR}/asm-ig/base
      
      cat <<EOF > ${WORKDIR}/asm-ig/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/anthos-service-mesh-samples/docs/ingress-gateway-asm-manifests/base
      EOF
      
      mkdir ${WORKDIR}/asm-ig/variant
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/role.yaml
      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      rules:
      - apiGroups: [""]
        resources: ["secrets"]
        verbs: ["get", "watch", "list"]
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/rolebinding.yaml
      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
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/service-proto-type.yaml
      apiVersion: v1
      kind: Service
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      spec:
        ports:
        - name: status-port
          port: 15021
          protocol: TCP
          targetPort: 15021
        - name: http
          port: 80
          targetPort: 8080
          appProtocol: HTTP
        - name: https
          port: 443
          targetPort: 8443
          appProtocol: HTTP2
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/gateway.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      spec:
       servers:
        - port:
            number: 443
            name: https
            protocol: HTTPS
          hosts:
          - "*" # IMPORTANT: Must use wildcard here when using SSL, as SNI isn't passed from GFE
          tls:
            mode: SIMPLE
            credentialName: edge2mesh-credential
      EOF
      
      cat <<EOF > ${WORKDIR}/asm-ig/variant/kustomization.yaml
      namespace: asm-ingress
      resources:
      - ../base
      - role.yaml
      - rolebinding.yaml
      patches:
      - path: service-proto-type.yaml
        target:
          kind: Service
      - path: gateway.yaml
        target:
          kind: Gateway
      EOF
      
    6. Aplique a configuração do gateway de entrada aos dois clusters:

      kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant
      kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
      

    Expor pods de gateway de entrada ao balanceador de carga usando um serviço de vários clusters

    Nesta seção, você exporta os pods de gateway de entrada usando um recurso personalizado ServiceExport. É necessário exportar os pods de gateway de entrada por um recurso personalizado ServiceExport pelos seguintes motivos:

    1. No Cloud Shell, ative os serviços de vários clusters (MCS) para a frota:

      gcloud container fleet multi-cluster-services enable
      
    2. Conceda ao MCS as permissões do IAM necessárias para o projeto ou a frota:

      gcloud projects add-iam-policy-binding PROJECT_ID \
       --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
       --role "roles/compute.networkViewer"
      
    3. Crie o arquivo YAML ServiceExport:

      cat <<EOF > ${WORKDIR}/svc_export.yaml
      kind: ServiceExport
      apiVersion: net.gke.io/v1
      metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
      EOF
      
    4. Aplique o arquivo YAML ServiceExport aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yaml
      

      Se você receber a mensagem de erro a seguir, aguarde alguns instantes para que as definições de recursos personalizados (CRDs) do MCS sejam instaladas. Em seguida, execute novamente os comandos para aplicar o arquivo YAML ServiceExport aos dois clusters.

      error: resource mapping not found for name: "asm-ingressgateway" namespace: "asm-ingress" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1"
      ensure CRDs are installed first
      

    Criar recursos de endereço IP externo, registro DNS e certificado TLS

    Nesta seção, você cria recursos de rede que são compatíveis com os recursos de balanceamento de carga que serão criados mais adiante nesta implantação.

    1. No Cloud Shell, reserve um endereço IP externo estático:

      gcloud compute addresses create mcg-ip --global
      

      Um endereço IP estático é usado pelo recurso de gateway do GKE. Ele permite que o endereço IP permaneça o mesmo, mesmo que o balanceador de carga externo seja recriado.

    2. Acesse o endereço IP estático e armazene-o como uma variável de ambiente:

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

      Para criar um mapeamento estável e legível por humanos para o endereço IP do Gateway, é preciso ter um registro DNS público.

      Use o provedor de DNS e o esquema de automação que quiser. Nesta implantação, usamos os Endpoints em vez de criar uma zona de DNS gerenciada. Os Endpoints fornecem um registro DNS gerenciado pelo Google gratuito para um endereço IP externo.

    3. Execute o comando abaixo para criar um arquivo YAML chamado dns-spec.yaml:

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

      O arquivo dns-spec.yaml define o registro DNS público no formato frontend.endpoints.PROJECT_ID.cloud.goog, em que PROJECT_ID é o identificador exclusivo do projeto.

    4. Implante o arquivo dns-spec.yaml para criar a entrada DNS. Esse processo leva alguns minutos.

      gcloud endpoints services deploy ${WORKDIR}/dns-spec.yaml
      
    5. Crie um certificado usando o Gerenciador de certificados para o nome da entrada DNS criado na etapa anterior:

      gcloud certificate-manager certificates create mcg-cert \
          --domains="frontend.endpoints.PROJECT_ID.cloud.goog"
      

      Um certificado TLS gerenciado pelo Google é usado para encerrar solicitações de clientes de entrada no balanceador de carga.

    6. Criar um mapa de certificado:

      gcloud certificate-manager maps create mcg-cert-map
      

      O balanceador de carga faz referência ao certificado pela entrada do mapa de certificado criada na próxima etapa.

    7. Crie uma entrada de mapa de certificados para o certificado que você criou anteriormente nesta seção:

      gcloud certificate-manager maps entries create mcg-cert-map-entry \
          --map="mcg-cert-map" \
          --certificates="mcg-cert" \
          --hostname="frontend.endpoints.PROJECT_ID.cloud.goog"
      

    Criar políticas de serviço de back-end e recursos de balanceador de carga

    Nesta seção, você vai realizar as seguintes tarefas:

    • Crie uma política de segurança do Cloud Armor com regras.
    • Crie uma política que permita que o balanceador de carga verifique a capacidade de resposta dos pods do gateway de entrada usando o arquivo YAML ServiceExport que você criou anteriormente.
    • Use a API Gateway do GKE para criar um recurso de balanceador de carga.
    • Use o recurso personalizado GatewayClass para definir o tipo específico de balanceador de carga.
    • Ative o balanceamento de carga de vários clusters para a frota e designe um dos clusters como o cluster de configuração da frota.
    1. No Cloud Shell, crie uma política de segurança do Cloud Armor:

      gcloud compute security-policies create edge-fw-policy \
          --description "Block XSS attacks"
      
    2. Crie uma regra para sua política de segurança:

      gcloud compute security-policies rules create 1000 \
          --security-policy edge-fw-policy \
          --expression "evaluatePreconfiguredExpr('xss-stable')" \
          --action "deny-403" \
          --description "XSS attack filtering"
      
    3. Crie um arquivo YAML para a política de segurança e faça referência ao arquivo YAML ServiceExport usando um arquivo YAML ServiceImport correspondente:

      cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml
      apiVersion: networking.gke.io/v1
      kind: GCPBackendPolicy
      metadata:
        name: cloud-armor-backendpolicy
        namespace: asm-ingress
      spec:
        default:
          securityPolicy: edge-fw-policy
        targetRef:
          group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
      EOF
      
    4. Aplique a política do Cloud Armor aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    5. Crie um arquivo YAML personalizado que permita que o balanceador de carga realize verificações de integridade no endpoint de integridade do Envoy (porta 15021 no caminho /healthz/ready) dos pods de gateway de entrada nos dois clusters:

      cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml
      apiVersion: networking.gke.io/v1
      kind: HealthCheckPolicy
      metadata:
        name: ingress-gateway-healthcheck
        namespace: asm-ingress
      spec:
        default:
          config:
            httpHealthCheck:
              port: 15021
              portSpecification: USE_FIXED_PORT
              requestPath: /healthz/ready
            type: HTTP
        targetRef:
          group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
      EOF
      
    6. Aplique o arquivo YAML personalizado que você criou na etapa anterior aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      
    7. Ative o balanceamento de carga de vários clusters para a frota e designe CLUSTER_1_NAME como o cluster de configuração:

      gcloud container fleet ingress enable \
        --config-membership=${CLUSTER_1_NAME} \
        --location=${CLUSTER_1_REGION}
      
    8. Conceda as permissões do IAM para o controlador de gateway na frota:

      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \
          --role "roles/container.admin"
      
    9. Crie o arquivo YAML do balanceador de carga usando um recurso personalizado do Gateway que referencia o gke-l7-global-external-managed-mc gatewayClass e o endereço IP estático que você criou anteriormente:

      cat <<EOF > ${WORKDIR}/frontend-gateway.yaml
      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1
      metadata:
        name: external-http
        namespace: asm-ingress
        annotations:
          networking.gke.io/certmap: mcg-cert-map
      spec:
        gatewayClassName: gke-l7-global-external-managed-mc
        listeners:
        - name: http # list the port only so we can redirect any incoming http requests to https
          protocol: HTTP
          port: 80
        - name: https
          protocol: HTTPS
          port: 443
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
        addresses:
        - type: NamedAddress
          value: mcg-ip
      EOF
      
    10. Aplique o arquivo YAML frontend-gateway aos dois clusters. Somente CLUSTER_1_NAME é autoritativo, a menos que você designe um cluster de configuração diferente como autoritativo:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
      
    11. Crie um arquivo YAML HTTPRoute chamado default-httproute.yaml que instrua o recurso Gateway a enviar solicitações aos gateways de entrada:

      cat << EOF > ${WORKDIR}/default-httproute.yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: HTTPRoute
      metadata:
        name: default-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: https
        rules:
        - backendRefs:
          - group: net.gke.io
            kind: ServiceImport
            name: asm-ingressgateway
            port: 443
      EOF
      
    12. Aplique o arquivo YAML HTTPRoute criado na etapa anterior a ambos os clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
      
    13. Para realizar redirecionamentos HTTP para HTTP(S), crie outro arquivo YAML HTTPRoute chamado default-httproute-redirect.yaml:

      cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml
      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1
      metadata:
        name: http-to-https-redirect-httproute
        namespace: asm-ingress
      spec:
        parentRefs:
        - name: external-http
          namespace: asm-ingress
          sectionName: http
        rules:
        - filters:
          - type: RequestRedirect
            requestRedirect:
              scheme: https
              statusCode: 301
      EOF
      
    14. Aplique o arquivo YAML de redirecionamento HTTPRoute aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
      
    15. Inspecione o recurso Gateway para verificar o progresso da implantação do balanceador de carga:

      kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n asm-ingress
      

      A saída mostra as informações que você inseriu nesta seção.

    Implantar o aplicativo de exemplo whereami

    Este guia usa o whereami como um aplicativo de exemplo para fornecer feedback direto sobre quais clusters estão respondendo às solicitações. A seção a seguir configura duas implantações separadas do whereami nos dois clusters: uma implantação frontend e uma backend.

    A implantação frontend é a primeira carga de trabalho a receber a solicitação. Em seguida, ela chama a implantação backend.

    Esse modelo é usado para demonstrar uma arquitetura de aplicativo multiserviço. Os serviços frontend e backend são implantados nos dois clusters.

    1. No Cloud Shell, crie os namespaces para um frontend e um backend do whereami nos dois clusters e ative a injeção de namespace:

      kubectl --context=${CLUSTER_1_NAME} create ns frontend
      kubectl --context=${CLUSTER_1_NAME} label namespace frontend istio-injection=enabled
      kubectl --context=${CLUSTER_1_NAME} create ns backend
      kubectl --context=${CLUSTER_1_NAME} label namespace backend istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} create ns frontend
      kubectl --context=${CLUSTER_2_NAME} label namespace frontend istio-injection=enabled
      kubectl --context=${CLUSTER_2_NAME} create ns backend
      kubectl --context=${CLUSTER_2_NAME} label namespace backend istio-injection=enabled
      
    2. Crie uma variante do Kustomize para o backend do whereami:

      mkdir -p ${WORKDIR}/whereami-backend/base
      
      cat <<EOF > ${WORKDIR}/whereami-backend/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
      EOF
      
      mkdir ${WORKDIR}/whereami-backend/variant
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/cm-flag.yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: whereami
      data:
        BACKEND_ENABLED: "False" # assuming you don't want a chain of backend calls
        METADATA:        "backend"
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/service-type.yaml
      apiVersion: "v1"
      kind: "Service"
      metadata:
        name: "whereami"
      spec:
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-backend/variant/kustomization.yaml
      nameSuffix: "-backend"
      namespace: backend
      commonLabels:
        app: whereami-backend
      resources:
      - ../base
      patches:
      - path: cm-flag.yaml
        target:
          kind: ConfigMap
      - path: service-type.yaml
        target:
          kind: Service
      EOF
      
    3. Aplique a variante backend do whereami aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-backend/variant
      kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-backend/variant
      
    4. Crie uma variante do Kustomize para o frontend do whereami:

      mkdir -p ${WORKDIR}/whereami-frontend/base
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/base/kustomization.yaml
      resources:
        - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
      EOF
      
      mkdir whereami-frontend/variant
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/cm-flag.yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: whereami
      data:
        BACKEND_ENABLED: "True"
        BACKEND_SERVICE: "http://whereami-backend.backend.svc.cluster.local"
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/service-type.yaml
      apiVersion: "v1"
      kind: "Service"
      metadata:
        name: "whereami"
      spec:
        type: ClusterIP
      EOF
      
      cat <<EOF > ${WORKDIR}/whereami-frontend/variant/kustomization.yaml
      nameSuffix: "-frontend"
      namespace: frontend
      commonLabels:
        app: whereami-frontend
      resources:
      - ../base
      patches:
      - path: cm-flag.yaml
        target:
          kind: ConfigMap
      - path: service-type.yaml
        target:
          kind: Service
      EOF
      
    5. Aplique a variante frontend do whereami aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
      kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
      
    6. Crie um arquivo YAML VirtualService para encaminhar solicitações para o frontend do whereami:

      cat << EOF > ${WORKDIR}/frontend-vs.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: whereami-vs
        namespace: frontend
      spec:
        gateways:
        - asm-ingress/asm-ingressgateway
        hosts:
        - 'frontend.endpoints.PROJECT_ID.cloud.goog'
        http:
        - route:
          - destination:
              host: whereami-frontend
              port:
                number: 80
      EOF
      
    7. Aplique o arquivo YAML frontend-vs aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
      
    8. Agora que você implantou frontend-vs.yaml nos dois clusters, tente chamar o endpoint público deles:

      curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
      

      O resultado será assim:

      {
        "backend_result": {
          "cluster_name": "edge-to-mesh-02",
          "gce_instance_id": "8396338201253702608",
          "gce_service_account": "e2m-mcg-01.svc.id.goog",
          "host_header": "whereami-backend.backend.svc.cluster.local",
          "metadata": "backend",
          "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-645h",
          "pod_ip": "10.124.0.199",
          "pod_name": "whereami-backend-7cbdfd788-8mmnq",
          "pod_name_emoji": "📸",
          "pod_namespace": "backend",
          "pod_service_account": "whereami-backend",
          "project_id": "e2m-mcg-01",
          "timestamp": "2023-12-01T03:46:24",
          "zone": "us-east4-b"
        },
        "cluster_name": "edge-to-mesh-01",
        "gce_instance_id": "1047264075324910451",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
        "metadata": "frontend",
        "node_name": "gk3-edge-to-mesh-01-pool-2-d687e3c0-5kf2",
        "pod_ip": "10.54.1.71",
        "pod_name": "whereami-frontend-69c4c867cb-dgg8t",
        "pod_name_emoji": "🪴",
        "pod_namespace": "frontend",
        "pod_service_account": "whereami-frontend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T03:46:24",
        "zone": "us-central1-c"
      }
      

    Se você executar o comando curl algumas vezes, verá que as respostas (de frontend e backend) vêm de regiões diferentes. Em resposta, o balanceador de carga está fornecendo o roteamento geográfico. Isso significa que o balanceador de carga está roteando solicitações do cliente para o cluster ativo mais próximo, mas as solicitações ainda estão sendo enviadas aleatoriamente. Quando as solicitações vão de uma região para outra, isso aumenta a latência e o custo.

    Na próxima seção, você vai implementar o balanceamento de carga de localidade no Service Mesh para manter as solicitações locais.

    Ativar e testar o balanceamento de carga de localidade para o whereami

    Nesta seção, você vai implementar o balanceamento de carga de localidade na malha de serviço para manter as solicitações locais. Você também realiza alguns testes para conferir como o whereami processa vários cenários de falha.

    Quando você faz uma solicitação para o serviço frontend do whereami, o balanceador de carga envia a solicitação para o cluster com a menor latência em relação ao cliente. Isso significa que os pods de gateway de entrada dentro do balanceamento de carga de malha solicita pods frontend do whereami nos dois clusters. Esta seção vai resolver esse problema ativando o balanceamento de carga de localidade na malha.

    1. No Cloud Shell, crie um arquivo YAML DestinationRule que ative o failover regional de balanceamento de carga de localidade para o serviço frontend:

      cat << EOF > ${WORKDIR}/frontend-dr.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: frontend
        namespace: frontend
      spec:
        host: whereami-frontend.frontend.svc.cluster.local
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 0
          loadBalancer:
            simple: LEAST_REQUEST
            localityLbSetting:
              enabled: true
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 1s
            baseEjectionTime: 1m
      EOF
      

      O exemplo de código anterior só ativa o roteamento local para o serviço frontend. Você também precisa de uma configuração extra que processe o back-end.

    2. Aplique o arquivo YAML frontend-dr aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
      
    3. Crie um arquivo YAML DestinationRule que ative o failover regional de balanceamento de carga de localidade para o serviço backend:

      cat << EOF > ${WORKDIR}/backend-dr.yaml
      apiVersion: networking.istio.io/v1beta1
      kind: DestinationRule
      metadata:
        name: backend
        namespace: backend
      spec:
        host: whereami-backend.backend.svc.cluster.local
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 0
          loadBalancer:
            simple: LEAST_REQUEST
            localityLbSetting:
              enabled: true
          outlierDetection:
            consecutive5xxErrors: 1
            interval: 1s
            baseEjectionTime: 1m
      EOF
      
    4. Aplique o arquivo YAML backend-dr aos dois clusters:

      kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml
      kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yaml
      

      Com os dois conjuntos de arquivos YAML DestinationRule aplicados aos dois clusters, as solicitações permanecem locais para o cluster para o qual a solicitação é roteada.

      Para testar o failover do serviço frontend, reduza o número de réplicas do gateway de entrada no cluster principal.

      Do ponto de vista do balanceador de carga multirregional, essa ação simula uma falha de cluster. Isso faz com que o cluster falhe nas verificações de integridade do balanceador de carga. Este exemplo usa o cluster em CLUSTER_1_REGION. Você só vai ver respostas do cluster em CLUSTER_2_REGION.

    5. Reduza o número de réplicas do gateway de entrada no cluster principal para zero e chame o endpoint público para verificar se as solicitações falharam no outro cluster:

      kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=0 deployment/asm-ingressgateway
      

      A saída será semelhante a esta:

      $ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
      {
        "backend_result": {
          "cluster_name": "edge-to-mesh-02",
          "gce_instance_id": "2717459599837162415",
          "gce_service_account": "e2m-mcg-01.svc.id.goog",
          "host_header": "whereami-backend.backend.svc.cluster.local",
          "metadata": "backend",
          "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2",
          "pod_ip": "10.124.1.7",
          "pod_name": "whereami-backend-7cbdfd788-mp8zv",
          "pod_name_emoji": "🏌🏽‍♀",
          "pod_namespace": "backend",
          "pod_service_account": "whereami-backend",
          "project_id": "e2m-mcg-01",
          "timestamp": "2023-12-01T05:41:18",
          "zone": "us-east4-b"
        },
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "6983018919754001204",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
        "metadata": "frontend",
        "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn",
        "pod_ip": "10.124.1.142",
        "pod_name": "whereami-frontend-69c4c867cb-xf8db",
        "pod_name_emoji": "🏴",
        "pod_namespace": "frontend",
        "pod_service_account": "whereami-frontend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T05:41:18",
        "zone": "us-east4-b"
      }
      
    6. Para retomar o roteamento de tráfego normal, restaure as réplicas do gateway de entrada para o valor original no cluster:

      kubectl --context=${CLUSTER_1_NAME} -n asm-ingress scale --replicas=3 deployment/asm-ingressgateway
      
    7. Simule uma falha no serviço backend reduzindo o número de réplicas na região principal para 0:

      kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backend
      

      Verifique se as respostas do serviço frontend vêm da região principal us-central1 pelo balanceador de carga e se as respostas do serviço backend vêm da região secundária us-east4.

      A saída também precisa incluir uma resposta para o serviço frontend da região principal (us-central1) e uma resposta para o serviço backend da região secundária (us-east4), conforme esperado.

    8. Restaure as réplicas do serviço de back-end para o valor original para retomar o roteamento de tráfego típico:

      kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
      

    Agora você tem um balanceador de carga HTTP(S) global que serve como front-end para seu aplicativo multirregional hospedado pela malha de serviço.

    Limpar

    Para evitar cobranças na sua conta do Google Cloud pelos recursos usados nesta implantação, exclua o projeto que contém os recursos ou mantenha o projeto e exclua os recursos individuais.

    Excluir o projeto

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    Excluir recursos individuais

    Se você quiser manter o projeto Google Cloud usado nesta implantação, exclua os recursos individuais:

    1. No Cloud Shell, exclua os recursos HTTPRoute:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
      
    2. Exclua os recursos do gateway do GKE:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
      
    3. Exclua as políticas:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
      
    4. Exclua as exportações de serviço:

      kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml
      kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
      
    5. Exclua os recursos do Cloud Armor:

      gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet
      gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
      
    6. Exclua os recursos do Gerenciador de certificados:

      gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet
      gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet
      gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
      
    7. Exclua a entrada DNS do Endpoints:

      gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
      
    8. Exclua o endereço IP estático:

      gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
      
    9. Exclua os clusters do GKE Autopilot. Essa etapa leva alguns minutos.

      gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} --quiet
      gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} --quiet
      

    A seguir

    Colaboradores

    Autores:

    Outros colaboradores: