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ê usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

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

    Go to project selector

  2. Make sure 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 padrão do Google Cloud:

    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`
    

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 Google 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 Google 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 Google 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:
    n    ame: 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 na implantação, exclua o projeto ou mantenha o projeto e exclua cada um dos recursos.

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 do 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. Excluir os recursos do Google 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: