Implantar um aplicativo de contêiner altamente disponível

Nesta página, você encontra a estratégia de implantação recomendada para criar um aplicativo de contêiner do Kubernetes robusto e de alta disponibilidade (HA) no Google Distributed Cloud (GDC) isolado por air-gap. É necessário implantar o aplicativo de contêiner em várias zonas do GDC e configurar a replicação de armazenamento assíncrona para que o aplicativo e os dados possam ser recuperados em caso de inatividade inesperada ou desastre local.

Esta página é destinada a desenvolvedores do grupo de operadores de aplicativos, que são responsáveis por criar cargas de trabalho de aplicativos para a organização. Para mais informações, consulte Públicos-alvo para documentação isolada do GDC.

Objetivos

  • Crie um cluster do Kubernetes em duas ou mais zonas no seu universo do GDC.
  • Configure o balanceamento de carga global.
  • Implante cargas de trabalho de contêiner em cada cluster zonal do Kubernetes.
  • Provisione o armazenamento e anexe-o aos seus pods.
  • Configure a replicação assíncrona de armazenamento usando armazenamento de blocos ou de objetos.

Antes de começar

  • Verifique se você está trabalhando em um universo do GDC com várias zonas disponíveis. Execute gdcloud zones list para listar as zonas disponíveis no seu universo. Para mais informações, consulte Listar zonas em um universo.

  • Peça ao administrador do IAM da organização para conceder a você os seguintes papéis:

    • A função de administrador de namespace (namespace-admin) para criar e gerenciar cargas de trabalho de contêineres.

    • As funções de administrador do cluster de usuário (user-cluster-admin) e desenvolvedor do cluster de usuário (user-cluster-developer) para criar e gerenciar clusters do Kubernetes e seus pools de nós.

    • Os papéis "Administrador do balanceador de carga" (load-balancer-admin) e "Administrador do balanceador de carga global" (global-load-balancer-admin). Você precisa ter essa função para criar e gerenciar balanceadores de carga.

    • A função de administrador global de replicação de volume (app-volume-replication-admin-global). É necessário ter essa função para administrar a replicação de volume.

    • A função de administrador global do PNP (global-project-networkpolicy-admin) para criar e gerenciar políticas de rede do projeto em todas as zonas.

    • Os papéis Administrador da instância do Harbor (harbor-instance-admin), Leitor da instância do Harbor(harbor-instance-viewer) e Criador de projetos do Harbor (harbor-project-creator). Essas funções são necessárias para criar e gerenciar imagens de contêiner no Artifact Registry.

    • O papel de administrador global da replicação de volume (app-volume-replication-admin-global) para administrar a relação de replicação de volume para recursos de armazenamento em blocos.

    • Os papéis Administrador de objetos do bucket do projeto (project-bucket-object-admin) e Administrador do bucket do projeto (project-bucket-admin) para criar e gerenciar buckets de armazenamento.

    Consulte as descrições de papéis para mais informações.

  • Instale e configure a CLI gdcloud e configure os contextos zonal e global. Consulte Gerenciar recursos em várias zonas para mais informações.

  • Instale e configure a CLI kubectl com os arquivos kubeconfig adequados definidos para o servidor da API global, o servidor da API Management e o cluster do Kubernetes. Consulte Gerar manualmente o arquivo kubeconfig para mais informações.

Criar um cluster do Kubernetes em várias zonas

Um cluster do Kubernetes é um recurso zonal. Portanto, é necessário criar um cluster separado em cada zona.

Console

  1. No menu de navegação, selecione Kubernetes Engine > Clusters.

  2. Clique em Criar cluster.

  3. No campo Nome, especifique um nome para o cluster.

  4. Selecione a versão do Kubernetes para o cluster.

  5. Selecione a zona em que o cluster será criado.

  6. Clique em Anexar projeto e selecione um projeto para anexar ao cluster. Clique em Salvar. É possível anexar ou desanexar projetos depois de criar o cluster na página Detalhes do projeto. É necessário ter um projeto anexado ao cluster antes de implantar cargas de trabalho de contêineres nele.

  7. Clique em Próxima.

  8. Configure as definições de rede do cluster. Não é possível mudar essas configurações de rede depois de criar o cluster. O protocolo de Internet padrão e único compatível com clusters do Kubernetes é o protocolo de Internet versão 4 (IPv4).

    1. Especifique o tamanho do pool de endereços IP do balanceador de carga, como 20.

    2. Selecione o CIDR (roteamento entre domínios sem classe) de serviço a ser usado. Seus serviços implantados, como balanceadores de carga, recebem endereços IP desse intervalo.

    3. Selecione o CIDR do pod a ser usado. O cluster aloca endereços IP desse intervalo para seus pods e VMs.

    4. Clique em Próxima.

  9. Revise os detalhes do pool de nós padrão gerado automaticamente para o cluster. Clique em Editar para modificar o pool de nós padrão.

  10. Para criar outros pools de nós, selecione Adicionar pool de nós. Ao editar o pool de nós padrão ou adicionar um novo, personalize-o com as seguintes opções:

    1. Atribua um nome ao pool de nós. Não é possível modificar o nome depois de criar o pool de nós.
    2. Especifique o número de nós de trabalho a serem criados no pool de nós.
    3. Selecione a classe de máquina mais adequada para os requisitos da sua carga de trabalho. Confira a lista das seguintes configurações:

      • Tipo de máquina
      • CPU
      • Memória
    4. Clique em Salvar.

    5. Clique em Criar para gerar o cluster.

  11. Repita essas etapas para cada zona no seu universo do GDC. Verifique se um cluster do Kubernetes está em cada zona que você quer para sua estratégia de alta disponibilidade.

API

Para criar um cluster do Kubernetes usando a API diretamente, aplique um recurso personalizado a cada zona do GDC.

  1. Crie um recurso personalizado Cluster e implante-o no servidor da API Management para sua zona:

    kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f - <<EOF \
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: CLUSTER_NAME
      namespace: platform
    spec:
      clusterNetwork:
        podCIDRSize: POD_CIDR
        serviceCIDRSize: SERVICE_CIDR
      initialVersion:
        kubernetesVersion: KUBERNETES_VERSION
      loadBalancer:
        ingressServiceIPSize: LOAD_BALANCER_POOL_SIZE
      nodePools:
      - machineTypeName: MACHINE_TYPE
        name: NODE_POOL_NAME
        nodeCount: NUMBER_OF_WORKER_NODES
        taints: TAINTS
        labels: LABELS
        acceleratorOptions:
          gpuPartitionScheme: GPU_PARTITION_SCHEME
      releaseChannel:
        channel: UNSPECIFIED
    EOF
    

    Substitua:

    • MANAGEMENT_API_SERVER: o caminho kubeconfig do servidor da API Management zonal. Para mais informações, consulte Mudar para o contexto zonal.
    • CLUSTER_NAME: o nome do cluster. O nome do cluster não pode terminar com -system. O sufixo -system é reservado para clusters criados pelo GDC.
    • POD_CIDR: o tamanho dos intervalos de rede de que os endereços IP virtuais (VIPs) do pod são alocados. Se não for definido, o valor padrão 21 será usado.
    • SERVICE_CIDR: o tamanho dos intervalos de rede de que os VIPs de serviço são alocados. Se não estiver definido, o valor padrão 23 será usado.
    • KUBERNETES_VERSION: a versão do Kubernetes do cluster, como 1.26.5-gke.2100. Para listar as versões disponíveis do Kubernetes para configuração, consulte Listar as versões disponíveis do Kubernetes para um cluster.
    • LOAD_BALANCER_POOL_SIZE: o tamanho dos pools de endereços IP não sobrepostos usados pelos serviços de balanceador de carga. Se não for definido, o valor padrão 20 será usado.
    • MACHINE_TYPE: o tipo de máquina para os nós de trabalho do pool de nós. Consulte os tipos de máquina disponíveis para saber o que pode ser configurado.
    • NODE_POOL_NAME: o nome do pool de nós.
    • NUMBER_OF_WORKER_NODES: o número de nós de trabalho a serem provisionados no pool de nós.
    • TAINTS: os taints a serem aplicados aos nós deste pool de nós. Esse campo é opcional.
    • LABELS: os rótulos a serem aplicados aos nós deste pool de nós. Ele contém uma lista de pares de chave-valor. Esse campo é opcional.
    • GPU_PARTITION_SCHEME: o esquema de particionamento de GPU, se você estiver executando cargas de trabalho de GPU, como mixed-2. A GPU não será particionada se esse campo não for definido. Para ver os perfis de GPU de várias instâncias (MIG) disponíveis, consulte Perfis de MIG compatíveis.
  2. Repita a etapa anterior para cada zona em que você quer hospedar o aplicativo de contêiner para sua estratégia de alta disponibilidade.

Configurar balanceadores de carga

Para distribuir o tráfego entre seus pods em diferentes zonas, crie balanceadores de carga. Você pode criar balanceadores de carga externos (ELB) e balanceadores de carga internos (ILB), que podem ser configurados por zona ou globalmente. Neste exemplo, configure um ILB e um ELB globais para seu aplicativo de contêiner.

Criar um balanceador de carga interno global

Os balanceadores de carga internos (ILB, na sigla em inglês) expõem serviços dentro da organização de um pool de endereços IP internos atribuído a ela. Um serviço ILB nunca é acessível de qualquer endpoint fora da organização.

Conclua as etapas a seguir para criar um ILB global para suas cargas de trabalho de contêiner.

gdcloud

Crie um ILB que tenha como destino cargas de trabalho de pods usando a CLI gdcloud.

Esse ILB tem como destino todas as cargas de trabalho no projeto que correspondem ao rótulo definido no objeto Backend. O recurso personalizado Backend precisa ser definido como uma zona.

Para criar um ILB usando a CLI gdcloud, siga estas etapas:

  1. Crie um recurso zonal Backend em cada zona em que seus pods estão em execução para definir o endpoint do ILB:

    gdcloud compute backends create BACKEND_NAME \
        --labels=LABELS \
        --project=PROJECT \
        --cluster=CLUSTER_NAME \
        --zone=ZONE
    

    Substitua:

    • BACKEND_NAME: o nome escolhido para o recurso de back-end, como my-backend.
    • LABELS: o seletor que define quais endpoints entre pods usar para esse recurso de back-end, como app=web.
    • PROJECT: o nome do projeto.
    • CLUSTER_NAME: o cluster do Kubernetes a que o escopo dos seletores definidos é limitado. Se este campo não for especificado, todos os endpoints com o rótulo indicado serão selecionados. Este campo é opcional.
    • ZONE: a zona a ser usada para essa invocação. Para predefinir a flag de zona para todos os comandos que a exigem, execute gdcloud config set core/zone ZONE. A flag de zona só está disponível em ambientes multizonais. Este campo é opcional.

    Repita essa etapa para cada zona no seu universo do GDC.

  2. Crie um recurso BackendService global:

    gdcloud compute backend-services create BACKEND_SERVICE_NAME \
        --project=PROJECT \
        --target-ports=TARGET_PORTS \
        --global
    

    Substitua:

    • BACKEND_SERVICE_NAME: o nome do serviço de back-end.
    • PROJECT: o nome do projeto.
    • TARGET_PORTS: uma lista separada por vírgulas de portas de destino que esse serviço de back-end traduz, em que cada porta de destino especifica o protocolo, a porta na regra de encaminhamento e a porta na instância de back-end. É possível especificar várias portas de destino. Esse campo precisa estar no formato protocol:port:targetport, como TCP:80:8080. Este campo é opcional.
  3. Adicione o recurso BackendService ao recurso Backend criado anteriormente em cada zona:

    gdcloud compute backend-services add-backend BACKEND_SERVICE_NAME \
        --backend-zone=ZONE \
        --backend=BACKEND_NAME \
        --project=PROJECT \
        --global
    

    Substitua:

    • BACKEND_SERVICE_NAME: o nome do serviço de back-end global.
    • ZONE: a zona do back-end.
    • BACKEND_NAME: o nome do back-end zonal.
    • PROJECT: o nome do projeto.

    Conclua esta etapa para cada back-end zonal criado anteriormente.

  4. Crie um recurso ForwardingRule interno que defina o endereço IP virtual (VIP) em que o serviço está disponível:

    gdcloud compute forwarding-rules create FORWARDING_RULE_INTERNAL_NAME \
        --backend-service=BACKEND_SERVICE_NAME \
        --cidr=CIDR \
        --ip-protocol-port=PROTOCOL_PORT \
        --load-balancing-scheme=INTERNAL \
        --project=PROJECT \
        --global
    

    Substitua:

    • FORWARDING_RULE_INTERNAL_NAME: o nome da regra de encaminhamento.
    • CIDR: o CIDR a ser usado na regra de encaminhamento. Este campo é opcional. Se não for especificado, um CIDR IPv4/32 será reservado automaticamente do pool global de endereços IP. Especifique o nome de um recurso Subnet no mesmo namespace que esta regra de encaminhamento. Um recurso Subnet representa as informações de solicitação e alocação de uma sub-rede global. Para mais informações sobre recursos Subnet, consulte Gerenciar sub-redes.
    • PROTOCOL_PORT: o protocolo e a porta a serem expostos na regra de encaminhamento. Esse campo precisa estar no formato ip-protocol=TCP:80. A porta exposta precisa ser a mesma que o aplicativo real está expondo dentro do contêiner.
  5. Para validar o ILB configurado, confirme a condição Ready em cada um dos objetos criados. Verifique o tráfego com uma solicitação curl para o VIP:

    1. Para receber o VIP atribuído, descreva a regra de encaminhamento:

      gdcloud compute forwarding-rules describe FORWARDING_RULE_INTERNAL_NAME --global
      
    2. Verifique o tráfego com uma solicitação curl para o VIP na porta especificada no campo da regra de encaminhamento:

      curl http://FORWARDING_RULE_VIP:PORT
      

    Substitua:

    • FORWARDING_RULE_VIP: o VIP da regra de encaminhamento.
    • PORT: o número da porta da regra de encaminhamento.

API

Crie um ILB que tenha como destino cargas de trabalho de contêiner usando a API KRM. Esse ILB tem como destino todas as cargas de trabalho no projeto que correspondem ao rótulo definido no objeto Backend. Para criar um ILB global usando a API KRM, siga estas etapas:

  1. Crie um recurso Backend para definir os endpoints do ILB. Crie recursos Backend para cada zona em que as cargas de trabalho de contêineres estão localizadas:

    kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f - <<EOF
    apiVersion: networking.gdc.goog/v1
    kind: Backend
    metadata:
      namespace: PROJECT
      name: BACKEND_NAME
    spec:
      clusterName: CLUSTER_NAME
      endpointsLabels:
        matchLabels:
          app: APP_NAME
    EOF
    

    Substitua:

    • MANAGEMENT_API_SERVER: o caminho kubeconfig do servidor da API Management zonal. Para mais informações, consulte Mudar para um contexto zonal.
    • PROJECT: o nome do projeto.
    • BACKEND_NAME: o nome do recurso Backend.
    • CLUSTER_NAME: o cluster do Kubernetes a que o escopo dos seletores definidos é limitado. Se este campo não for especificado, todos os endpoints com o rótulo indicado serão selecionados. Este campo é opcional.
    • APP_NAME: o nome do seu aplicativo de contêiner.

    Você pode usar o mesmo recurso Backend para cada zona ou criar recursos Backend com conjuntos de rótulos diferentes para cada uma.

  2. Crie um objeto BackendService usando o recurso Backend criado anteriormente. Inclua o recurso HealthCheck:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: BackendService
    metadata:
      namespace: PROJECT
      name: BACKEND_SERVICE_NAME
    spec:
      backendRefs:
      - name: BACKEND_NAME
        zone: ZONE
      healthCheckName: HEALTH_CHECK_NAME
      targetPorts:
      - port: PORT
        protocol: PROTOCOL
        targetPort: TARGET_PORT
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o caminho kubeconfig do servidor da API global.
    • PROJECT: o nome do projeto.
    • BACKEND_SERVICE_NAME: o nome escolhido para o recurso BackendService.
    • HEALTH_CHECK_NAME: o nome do recurso HealthCheck criado anteriormente.
    • BACKEND_NAME: o nome do recurso zonal Backend.
    • ZONE: a zona em que o recurso Backend está localizado. É possível especificar vários back-ends no campo backendRefs. Exemplo:

      - name: my-backend-1
        zone: us-east1-a
      - name: my-backend-2
        zone: us-east1-b
      

      O campo targetPorts é opcional. Esse recurso lista as portas que o recurso BackendService traduz. Se você estiver usando esse objeto, forneça valores para o seguinte:

    • PORT: a porta exposta pelo serviço.

    • PROTOCOL: o protocolo da camada 4 que o tráfego precisa corresponder. Somente TCP e UDP são aceitos.

    • TARGET_PORT: a porta para a qual o valor é traduzido, como 8080. O valor não pode ser repetido em um determinado objeto.

      Um exemplo de targetPorts pode ser assim:

      targetPorts:
        - port: 80
          protocol: TCP
          targetPort: 8080
      
  3. Crie um recurso ForwardingRule interno que defina o endereço IP virtual (VIP) em que o serviço está disponível.

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ForwardingRuleInternal
    metadata:
      namespace: PROJECT
      name: FORWARDING_RULE_INTERNAL_NAME
    spec:
      cidrRef: CIDR
      ports:
      - port: PORT
        protocol: PROTOCOL
      backendServiceRef:
        name: BACKEND_SERVICE_NAME
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o caminho kubeconfig do servidor da API global.
    • PROJECT: o nome do projeto.
    • FORWARDING_RULE_INTERNAL_NAME: o nome escolhido para o recurso ForwardingRuleInternal.
    • CIDR: o CIDR a ser usado na regra de encaminhamento. Este campo é opcional. Se não for especificado, um CIDR IPv4/32 será reservado automaticamente do pool global de endereços IP. Especifique o nome de um recurso Subnet no mesmo namespace que esta regra de encaminhamento. Um recurso Subnet representa as informações de solicitação e alocação de uma sub-rede global. Para mais informações sobre recursos Subnet, consulte Gerenciar sub-redes.
    • PORT: a porta a ser exposta na regra de encaminhamento. Use o campo ports para especificar uma matriz de portas L4 para as quais os pacotes são encaminhados aos back-ends configurados com essa regra de encaminhamento. É necessário especificar pelo menos uma porta. Use o campo port para especificar um número de porta. A porta exposta precisa ser a mesma que o aplicativo real está expondo dentro do contêiner.
    • PROTOCOL: o protocolo a ser usado para a regra de encaminhamento, como TCP. Uma entrada na matriz ports precisa ser semelhante a esta:

      ports:
      - port: 80
        protocol: TCP
      
  4. Para validar o ILB configurado, confirme a condição Ready em cada um dos objetos criados. Verifique o tráfego com uma solicitação curl para o VIP:

    1. Recupere o VIP:

      kubectl get forwardingruleinternal -n PROJECT
      

      A saída será assim:

      NAME           BACKENDSERVICE                  CIDR              READY
      ilb-name       BACKEND_SERVICE_NAME            192.0.2.0/32      True
      
    2. Teste o tráfego com uma solicitação curl ao VIP na porta especificada no campo da regra de encaminhamento:

      curl http://FORWARDING_RULE_VIP:PORT
      

      Substitua:

      • FORWARDING_RULE_VIP: o VIP da regra de encaminhamento.
      • PORT: o número da porta do campo na regra de encaminhamento.

Criar um balanceador de carga externo global

Os balanceadores de carga externos (ELB, na sigla em inglês) expõem serviços para acesso de fora da organização de um pool de endereços IP atribuídos à organização do pool maior de endereços IP externo da instância.

Conclua as etapas a seguir para criar um ELB global para suas cargas de trabalho de contêiner.

gdcloud

Use a CLI gdcloud para criar um ELB global que tenha como destino todas as cargas de trabalho no projeto que correspondem ao rótulo definido no objeto Backend. O recurso personalizado Backend precisa ter escopo em uma zona.

  1. Para que os serviços do ELB funcionem, configure e aplique sua própria transferência de dados ProjectNetworkPolicy personalizada na política para permitir o tráfego para as cargas de trabalho desse serviço do ELB. As políticas de rede controlam o acesso às cargas de trabalho, não ao balanceador de carga em si. Os ELBs expõem cargas de trabalho à rede do cliente, exigindo políticas de rede explícitas para permitir o tráfego externo à porta da carga de trabalho, como 8080.

    Especifique o endereço CIDR externo para permitir o tráfego para as cargas de trabalho deste ELB:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ProjectNetworkPolicy
    metadata:
      namespace: PROJECT
      name: allow-inbound-traffic-from-external
    spec:
      policyType: Ingress
      subject:
        subjectType: UserWorkload
      ingress:
      - from:
        - ipBlock:
            cidr: CIDR
        ports:
        - protocol: TCP
          port: PORT
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o caminho kubeconfig do servidor de API global. Se você ainda não gerou um arquivo kubeconfig para o servidor da API global, consulte Gerar manualmente o arquivo kubeconfig para mais detalhes.
    • PROJECT: o nome do projeto.
    • CIDR: o CIDR externo de onde o ELB precisa ser acessado. Essa política é necessária porque o balanceador de carga externo usa o retorno direto do servidor (DSR), que preserva o endereço IP externo de origem e ignora o balanceador de carga no caminho de retorno. Para mais informações, consulte Criar uma regra de firewall de entrada global para tráfego entre organizações.
    • PORT: a porta de back-end nos pods atrás do balanceador de carga. Esse valor é encontrado no campo .spec.ports[].targetPortfield do manifesto do recurso Service. Este campo é opcional.

    Essa configuração fornece a todos os recursos dentro dos projetos acesso ao intervalo de CIDR especificado.

  2. Crie um recurso Backend em cada zona para definir o endpoint do ELB:

    gdcloud compute backends create BACKEND_NAME \
      --labels=LABELS \
      --project=PROJECT \
      --cluster=CLUSTER_NAME \
      --zone=ZONE
    

    Substitua:

    • BACKEND_NAME: o nome do recurso de back-end, como my-backend.
    • LABELS: um seletor que define quais endpoints entre pods usar para esse recurso de back-end, como app=web.
    • PROJECT: o nome do projeto.
    • CLUSTER_NAME: o cluster do Kubernetes a que o escopo dos seletores definidos é limitado. Se este campo não for especificado, todos os endpoints com o rótulo indicado serão selecionados. Este campo é opcional.
    • ZONE: a zona a ser usada para essa invocação. Para predefinir a flag de zona para todos os comandos que a exigem, execute gdcloud config set core/zone ZONE. A flag de zona só está disponível em ambientes multizonais. Este campo é opcional.

    Você pode usar o mesmo recurso Backend para cada zona ou criar recursos Backend com conjuntos de rótulos diferentes para cada uma.

  3. Crie um recurso BackendService global:

    gdcloud compute backend-services create BACKEND_SERVICE_NAME \
      --project=PROJECT \
      --target-ports=TARGET_PORTS \
      --health-check=HEALTH_CHECK_NAME \
      --global
    

    Substitua:

    • BACKEND_SERVICE_NAME: o nome escolhido para esse serviço de back-end.
    • PROJECT: o nome do projeto.
    • TARGET_PORTS: uma lista separada por vírgulas de portas de destino que esse serviço de back-end traduz. Cada porta de destino especifica o protocolo, a porta na regra de encaminhamento e a porta na instância de back-end. É possível especificar várias portas de destino. Esse campo precisa estar no formato protocol:port:targetport, como TCP:80:8080. Este campo é opcional.
    • HEALTH_CHECK_NAME: o nome do recurso de verificação de integridade. Este campo é opcional.
  4. Adicione o recurso global BackendService ao recurso zonal Backend criado anteriormente:

    gdcloud compute backend-services add-backend BACKEND_SERVICE_NAME \
      --backend=BACKEND_NAME \
      --backend-zone=ZONE \
      --project=PROJECT \
      --global
    

    Conclua esta etapa para cada back-end zonal criado anteriormente.

  5. Crie um recurso ForwardingRule externo que defina o VIP em que o serviço está disponível:

    gdcloud compute forwarding-rules create FORWARDING_RULE_EXTERNAL_NAME \
      --backend-service=BACKEND_SERVICE_NAME \
      --cidr=CIDR \
      --ip-protocol-port=PROTOCOL_PORT \
      --load-balancing-scheme=EXTERNAL \
      --project=PROJECT \
      --global
    

    Substitua:

    • FORWARDING_RULE_EXTERNAL_NAME: o nome da regra de encaminhamento.
    • CIDR: o CIDR a ser usado na regra de encaminhamento. Este campo é opcional. Se não for especificado, um CIDR IPv4/32 será reservado automaticamente do pool global de endereços IP. Especifique o nome de um recurso Subnet no mesmo namespace que esta regra de encaminhamento. Um recurso Subnet representa as informações de solicitação e alocação de uma sub-rede global. Para mais informações sobre recursos Subnet, consulte Gerenciar sub-redes.
    • PROTOCOL_PORT: o protocolo e a porta a serem expostos na regra de encaminhamento. Esse campo precisa estar no formato ip-protocol=TCP:80. A porta exposta precisa ser a mesma que o aplicativo está expondo dentro do contêiner.
    • PROJECT: o nome do projeto.
  6. Para validar o ELB configurado, confirme a condição Ready em cada um dos objetos criados. Verifique o tráfego com uma solicitação curl para o VIP:

    1. Para receber o VIP atribuído, descreva a regra de encaminhamento:

      gdcloud compute forwarding-rules describe FORWARDING_RULE_EXTERNAL_NAME
      
    2. Verifique o tráfego com uma solicitação curl para o VIP na porta especificada no campo PROTOCOL_PORT da regra de encaminhamento:

      curl http://FORWARDING_RULE_VIP:PORT
      

      Substitua:

      • FORWARDING_RULE_VIP: o VIP da regra de encaminhamento.
      • PORT: o número da porta do campo PROTOCOL_PORT na regra de encaminhamento.

API

Crie um ELB que tenha como destino cargas de trabalho de pod usando a API KRM. Esse ELB direciona todas as cargas de trabalho no projeto que correspondem ao rótulo definido no objeto Backend. Para criar um ELB zonal usando a API KRM, siga estas etapas:

  1. Para que os serviços do ELB funcionem, configure e aplique sua própria transferência de dados ProjectNetworkPolicy personalizada na política para permitir o tráfego para as cargas de trabalho desse serviço do ELB. As políticas de rede controlam o acesso às cargas de trabalho, não ao balanceador de carga em si. Os ELBs expõem cargas de trabalho à rede do cliente, exigindo políticas de rede explícitas para permitir o tráfego externo à porta da carga de trabalho, como 8080.

    Especifique o endereço CIDR externo para permitir o tráfego para as cargas de trabalho deste ELB:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ProjectNetworkPolicy
    metadata:
      namespace: PROJECT
      name: allow-inbound-traffic-from-external
    spec:
      policyType: Ingress
      subject:
        subjectType: UserWorkload
      ingress:
      - from:
        - ipBlock:
            cidr: CIDR
        ports:
        - protocol: TCP
          port: PORT
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o caminho kubeconfig do servidor de API global. Se você ainda não gerou um arquivo kubeconfig para o servidor da API global, consulte Gerar manualmente o arquivo kubeconfig para mais detalhes.
    • PROJECT: o nome do projeto.
    • CIDR: o CIDR externo de onde o ELB precisa ser acessado. Essa política é necessária porque o balanceador de carga externo usa o retorno direto do servidor (DSR), que preserva o endereço IP externo de origem e ignora o balanceador de carga no caminho de retorno. Para mais informações, consulte Criar uma regra de firewall de entrada global para tráfego entre organizações.
    • PORT: a porta de back-end nos pods atrás do balanceador de carga. Esse valor é encontrado no campo .spec.ports[].targetPortfield do manifesto do recurso Service. Este campo é opcional.
  2. Crie um recurso Backend para definir os endpoints do ELB. Crie recursos Backend para cada zona em que as cargas de trabalho estão localizadas:

    kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f - <<EOF
    apiVersion: networking.gdc.goog/v1
    kind: Backend
    metadata:
      namespace: PROJECT
      name: BACKEND_NAME
    spec:
      clusterName: CLUSTER_NAME
      endpointsLabels:
        matchLabels:
          app: APP_NAME
    EOF
    

    Substitua:

    • MANAGEMENT_API_SERVER: o caminho kubeconfig do servidor da API Management zonal. Se você ainda não gerou um arquivo kubeconfig para o servidor da API na zona de destino, consulte Gerar manualmente o arquivo kubeconfig para mais detalhes.
    • PROJECT: o nome do projeto.
    • BACKEND_NAME: o nome do recurso ;Backend
    • CLUSTER_NAME: o cluster do Kubernetes a que o escopo dos seletores definidos é limitado. Se este campo não for especificado, todos os endpoints com o rótulo indicado serão selecionados. Este campo é opcional.
    • APP_NAME: o nome do seu aplicativo de contêiner.

    Você pode usar o mesmo recurso Backend para cada zona ou criar recursos Backend com conjuntos de rótulos diferentes para cada uma.

  3. Crie um objeto BackendService usando o recurso Backend criado anteriormente:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: BackendService
    metadata:
      namespace: PROJECT
      name: BACKEND_SERVICE_NAME
    spec:
      backendRefs:
      - name: BACKEND_NAME
        zone: ZONE
      healthCheckName: HEALTH_CHECK_NAME
    EOF
    

    Substitua:

    • BACKEND_SERVICE_NAME: o nome escolhido para o recurso BackendService.
    • HEALTH_CHECK_NAME: o nome do recurso HealthCheck criado anteriormente. Não inclua esse campo se você estiver configurando um ELB para cargas de trabalho de pod.
    • ZONE: a zona em que o recurso Backend está localizado. É possível especificar vários back-ends no campo backendRefs. Exemplo:
    - name: my-backend-1
      zone: us-east1-a
    - name: my-backend-2
      zone: us-east1-b
    

  4. Crie um recurso ForwardingRule externo que defina o VIP em que o serviço está disponível.

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: networking.global.gdc.goog/v1
    kind: ForwardingRuleExternal
    metadata:
      namespace: PROJECT
      name: FORWARDING_RULE_EXTERNAL_NAME
    spec:
      cidrRef: CIDR
      ports:
      - port: PORT
        protocol: PROTOCOL
      backendServiceRef:
        name: BACKEND_SERVICE_NAME
    EOF
    

    Substitua:

    • FORWARDING_RULE_EXTERNAL_NAME: o nome escolhido para o recurso ForwardingRuleExternal.
    • CIDR: o CIDR a ser usado na regra de encaminhamento. Este campo é opcional. Se não for especificado, um CIDR IPv4/32 será reservado automaticamente do pool global de endereços IP. Especifique o nome de um recurso Subnet no mesmo namespace que esta regra de encaminhamento. Um recurso Subnet representa as informações de solicitação e alocação de uma sub-rede global. Para mais informações sobre recursos Subnet, consulte Gerenciar sub-redes.
    • PORT: a porta a ser exposta na regra de encaminhamento. Use o campo ports para especificar uma matriz de portas L4 em que os pacotes são encaminhados para os back-ends configurados com essa regra de encaminhamento. É necessário especificar pelo menos uma porta. Use o campo port para especificar um número de porta. A porta exposta precisa ser a mesma que o aplicativo real está expondo dentro do contêiner.
    • PROTOCOL: o protocolo a ser usado para a regra de encaminhamento, como TCP. Uma entrada na matriz ports precisa ser assim:
    ports:
    - port: 80
      protocol: TCP
    
  5. Para validar o ELB configurado, confirme a condição Ready em cada um dos objetos criados. Teste o tráfego com uma solicitação curl para o VIP.

    1. Recupere o VIP do projeto:

      kubectl get forwardingruleexternal -n PROJECT
      

      A saída será assim:

      NAME           BACKENDSERVICE                  CIDR              READY
      elb-name       BACKEND_SERVICE_NAME            192.0.2.0/32      True
      
    2. Verifique o tráfego com uma solicitação curl para o VIP na porta especificada no campo PORT da regra de encaminhamento:

      curl http://FORWARDING_RULE_VIP:PORT
      

      Substitua FORWARDING_RULE_VIP:PORT pelo VIP e pela porta da regra de encaminhamento, como 192.0.2.0:80.

Implante cargas de trabalho de contêineres em cada cluster zonal

As cargas de trabalho de contêiner não são um recurso global. Isso significa que você precisa implantar cada um dos aplicativos de contêiner separadamente nos clusters zonais do Kubernetes.

  1. Faça login na zona que hospeda seu cluster do Kubernetes:

    gdcloud config set core/zone ZONE
    
  2. Verifique se a imagem do contêiner está disponível no registro gerenciado do Harbor. Para mais informações, consulte o tutorial Implantar um app contêiner.

  3. Crie um arquivo de manifesto para sua carga de trabalho de contêiner e implante-o no cluster zonal do Kubernetes:

    kubectl --kubeconfig KUBERNETES_CLUSTER -n PROJECT \
        apply -f - <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: DEPLOYMENT_NAME
    spec:
      replicas: NUMBER_OF_REPLICAS
      selector:
        matchLabels:
          run: APP_NAME
      template:
        metadata:
          labels:
            run: APP_NAME
        spec:
          containers:
          - name: CONTAINER_NAME
            image: HARBOR_INSTANCE_URL/HARBOR_PROJECT_NAME/IMAGE:TAG
    EOF
    

    Substitua:

    • KUBERNETES_CLUSTER: o arquivo kubeconfig do cluster zonal do Kubernetes em que você está implantando cargas de trabalho de contêiner. Se você ainda não gerou um arquivo kubeconfig para seu cluster zonal do Kubernetes, consulte Gerar manualmente o arquivo kubeconfig para mais detalhes.
    • PROJECT: o namespace do projeto em que as cargas de trabalho de contêiner serão implantadas.
    • DEPLOYMENT_NAME: o nome da implantação do contêiner.
    • NUMBER_OF_REPLICAS: o número de objetos Pod replicados que a implantação gerencia.
    • APP_NAME: o nome do aplicativo a ser executado na implantação.
    • CONTAINER_NAME: o nome do contêiner.
    • HARBOR_INSTANCE_URL: o URL da instância do Harbor, como harbor-1.org-1.zone1.google.gdc.test.. Para recuperar o URL da instância do Harbor, consulte Ver instâncias do registro do Harbor.
    • HARBOR_PROJECT_NAME: o nome do projeto do Harbor, como my-project.
    • IMAGE: o nome da imagem, como nginx.
    • TAG: a tag da versão da imagem que você quer extrair, como 1.0.
  4. Repita as etapas anteriores para cada zona no seu universo do GDC. Verifique se o aplicativo de contêiner está em todas as zonas que você quer para sua estratégia de alta disponibilidade.

Exponha seu aplicativo de contêiner usando o Kubernetes

É necessário expor o aplicativo de contêiner para permitir o acesso a ele de outros recursos no universo do GDC.

  1. Crie um recurso Service de type: LoadBalancer. Esse recurso expõe os pods do aplicativo em uma rede.

    kubectl --kubeconfig KUBERNETES_CLUSTER -n PROJECT \
    apiVersion: v1
    kind: Service
    metadata:
      name: SERVICE_NAME
    spec:
      selector:
        app: APP_NAME
      ports:
        - port: 80
          protocol: TCP
      type: LoadBalancer
    EOF
    

    Substitua:

    • KUBERNETES_CLUSTER: o arquivo kubeconfig do cluster zonal do Kubernetes em que você está implantando cargas de trabalho de contêiner.
    • PROJECT: o namespace do projeto em que suas cargas de trabalho de contêiner residem.
    • SERVICE_NAME: o nome do serviço de balanceador de carga.
    • APP_NAME: o rótulo que você aplicou ao aplicativo de contêiner.
  2. Crie um recurso personalizado NetworkPolicy para permitir todo o tráfego de rede para o namespace padrão:

    kubectl --kubeconfig KUBERNETES_CLUSTER -n PROJECT \
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      annotations:
      name: allow-all
    spec:
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      podSelector: {}
      policyTypes:
      - Ingress
    EOF
    

Provisionar armazenamento permanente para seus pods

É necessário criar um recurso PersistentVolumeClaim (PVC) para fornecer armazenamento permanente aos pods de aplicativos.

As instruções a seguir mostram como criar um volume usando o GDC standard-rwo StorageClass.

  1. Criar um recurso PersistentVolumeClaim. Por exemplo, configure com um modo de acesso ReadWriteOnce e uma classe de armazenamento standard-rwo:

    kubectl --kubeconfig KUBERNETES_CLUSTER \
        --namespace PROJECT apply -f - <<EOF
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: PVC_NAME
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: standard-rwo
    EOF
    

    Substitua:

    • KUBERNETES_CLUSTER: o arquivo kubeconfig do cluster do Kubernetes.
    • PROJECT: o namespace do projeto em que a PVC será criada.
    • PVC_NAME: o nome do objeto PersistentVolumeClaim.
  2. Os objetos PersistentVolume (PV) são provisionados dinamicamente. Verifique o status dos novos PVs no cluster do Kubernetes:

    kubectl get pv --kubeconfig KUBERNETES_CLUSTER
    

    O resultado será assim:

    NAME       CAPACITY   ACCESS MODES   STATUS      CLAIM     STORAGECLASS   AGE
    pvc-uuidd  10Gi       RWO            Bound       pvc-name  standard-rwo   60s
    
  3. Configure suas cargas de trabalho de contêiner para usar o PVC. Confira a seguir um exemplo de manifesto de pod que usa um PVC standard-rwo:

    kubectl --kubeconfig KUBERNETES_CLUSTER \
        --namespace PROJECT apply -f - <<EOF
    apiVersion: apps/v1
    kind: Pod
    metadata:
      name: web-server-deployment
      labels:
        app: APP_LABEL
    spec:
      containers:
      - name: CONTAINER_NAME
        image: HARBOR_INSTANCE_URL/HARBOR_PROJECT_NAME/IMAGE:TAG
        volumeMounts:
        - mountPath: MOUNT_PATH
          name: data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: PVC_NAME
    EOF
    

    Substitua:

    • KUBERNETES_CLUSTER: o arquivo kubeconfig do cluster do Kubernetes em que você está implantando cargas de trabalho de contêiner.
    • PROJECT: o namespace do projeto em que a PVC está.
    • APP_LABEL: o rótulo que você aplicou ao aplicativo de contêiner.
    • CONTAINER_NAME: o nome do contêiner.
    • HARBOR_INSTANCE_URL: o URL da instância do Harbor, como harbor-1.org-1.zone1.google.gdc.test.. Para recuperar o URL da instância do Harbor, consulte Ver instâncias do registro do Harbor.
    • HARBOR_PROJECT_NAME: o nome do projeto do Harbor, como my-project.
    • IMAGE: o nome da imagem, como nginx.
    • TAG: a tag da versão da imagem que você quer extrair, como 1.0.
    • MOUNT_PATH: o caminho dentro do pod para montar o volume.
    • PVC_NAME: a PVC que você criou.

Configurar a replicação assíncrona de armazenamento

Os universos multizonais do GDC oferecem o uso de recursos de armazenamento replicados, como volumes e buckets, no modo assíncrono para cenários de recuperação de desastres. Essas opções de recursos de armazenamento oferecem replicação assíncrona de dados entre duas zonas na mesma região. A replicação assíncrona ocorre em segundo plano, fornecendo um objetivo de ponto de recuperação (RPO) baixo, mas não zero, em caso de desastre. Todos os dados replicados estão on-line e imediatamente acessíveis, mas podem exigir um procedimento manual de failover para permitir a gravação na zona secundária.

Você pode escolher um dos seguintes tipos de replicação de armazenamento assíncrona para seu aplicativo de contêiner:

Criar um bucket de duas zonas para armazenamento de objetos

Os dados de armazenamento de objetos são gravados em um único bucket, que armazena os dados nas duas zonas. Como os dados são copiados de forma assíncrona entre as zonas, elas podem não conter as mesmas versões de objetos a qualquer momento, mas vão se tornar equivalentes se nenhuma outra mudança for feita. Ao contrário da replicação de volume, os buckets replicados podem ser gravados durante as partições de zona. Cada gravação em um objeto produz uma versão diferente, e a versão mais recente em qualquer zona será o estado final após o restabelecimento da conectividade.

  1. Verifique se o operador de infraestrutura (IO) criou o recurso personalizado BucketLocationConfig, que é necessário para a replicação assíncrona entre zonas para armazenamento de objetos. Esse recurso precisa ser implantado no servidor da API global raiz.

  2. Crie o recurso personalizado Bucket de duas zonas:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: object.global.gdc.goog/v1
    kind: Bucket
    metadata:
      name: BUCKET_NAME
      namespace: PROJECT
    spec:
      location: LOCATION_NAME
      description: Sample DZ Bucket
      storageClass: Standard
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o arquivo kubeconfig do servidor da API global.
    • BUCKET_NAME: o nome do bucket de armazenamento.
    • PROJECT: o nome do projeto em que o bucket está.
    • LOCATION_NAME: o local físico em que os dados do objeto no bucket estão. Isso precisa ser mapeado para o nome de um recurso BucketLocation existente. Para consultar o servidor de API global da sua organização e ver uma lista de recursos BucketLocation disponíveis, execute kubectl --kubeconfig GLOBAL_API_SERVER bucketlocations. Se não houver recursos BucketLocation, entre em contato com seu IO para verificar se ele ativou a replicação assíncrona.

Configurar a replicação assíncrona do armazenamento em blocos entre zonas

O armazenamento em blocos replicado fornece volumes (PVs) replicados de forma assíncrona, que mantêm a equivalência de blocos entre os volumes primário e secundário. Devido à natureza assíncrona, o volume secundário reflete o estado da zona principal em algum momento do passado (RPO diferente de zero). O volume secundário não pode ser montado enquanto permanece como destino da replicação, exigindo intervenção manual para encerrar a relação e permitir que as gravações ocorram.

É necessário configurar uma relação de replicação de armazenamento entre zonas para criar dados replicados que estejam disponíveis para failover se os dados da zona de origem ficarem indisponíveis. Isso é relevante se você estiver usando armazenamento em blocos para o aplicativo de contêiner.

Antes de começar, verifique se o operador de infraestrutura (IO) criou e configurou os recursos personalizados StorageClusterPeering e StorageVirtualMachinePeering para permitir a replicação de armazenamento em blocos entre zonas. Esse recurso precisa ser implantado no servidor de API global raiz.

  1. Crie um arquivo YAML de recurso personalizado VolumeReplicationRelationship e implante-o no servidor de API global:

    kubectl --kubeconfig GLOBAL_API_SERVER apply -f - <<EOF
    apiVersion: storage.global.gdc.goog/v1
    kind: VolumeReplicationRelationship
    metadata:
      name: PVC_REPL_NAME
      namespace: PROJECT
    spec:
      source:
        pvc:
          clusterRef: SOURCE_PVC_CLUSTER
          pvcRef: SOURCE_PVC
        zoneRef: SOURCE_ZONE
    destination:
        pvc:
          clusterRef: DEST_PVC_CLUSTER
        zoneRef: DEST_ZONE
    EOF
    

    Substitua:

    • GLOBAL_API_SERVER: o arquivo kubeconfig do servidor de API global.
    • PVC_REPL_NAME: o nome da relação de replicação de volume.
    • PROJECT: o projeto em que a infraestrutura de armazenamento está localizada.
    • SOURCE_PVC_CLUSTER: o cluster do Kubernetes em que o PVC está hospedado.
    • SOURCE_PVC: o PVC na zona de origem a ser replicado.
    • SOURCE_ZONE: a zona de origem em que o PVC está hospedado.
    • DEST_PVC_CLUSTER: o cluster de destino do Kubernetes para replicar o PVC.
    • DEST_ZONE: a zona de destino para replicar o PVC.
  2. Crie um recurso personalizado VolumeFailover na zona de destino, que interrompe a replicação para a zona de destino se a zona de origem estiver indisponível por qualquer motivo:

    kubectl --kubeconfig MANAGEMENT_API_SERVER apply -f - <<EOF
    apiVersion: storage.gdc.goog/v1
    kind: VolumeFailover
    metadata:
      name: PVC_FAILOVER_NAME
      namespace: PROJECT
    spec:
      volumeReplicationRelationshipRef: PVC_REPL_NAME
    EOF
    

    Substitua:

    • MANAGEMENT_API_SERVER: o arquivo kubeconfig do servidor da API Management zonal.
    • PVC_FAILOVER_NAME: o nome do failover de PVC.
    • PROJECT: o projeto em que a infraestrutura de armazenamento está localizada.
    • PVC_REPL_NAME: o nome da relação de replicação de volume.

A seguir