Gerenciamento de endereços do GKE: como configurar NAT para um bloco de CIDR de pod do GKE

Este tutorial faz parte de uma série destinada a arquitetos de rede. A série discute as opções de gerenciamento de endereços do Google Kubernetes Engine (GKE) disponíveis para organizações restritas a endereços IPv4.

A série consiste nas partes a seguir:

Neste tutorial, mostramos como configurar uma solução na qual você atribui ao bloco de CIDR de pod um endereço RFC 1918 que já está em uso em uma rede local. Em seguida, traduza o bloco de CIDR (por NAT) usando o recurso ip-masq-agent. Essa abordagem oculta os endereços IPv4 do pod atrás dos endereços IP do nó. Em seguida, use Terraform para automatizar a versão da infraestrutura e use o SDK do Cloud para inspecionar os componentes mostrados na figura a seguir.

Como converter um bloco de CIDR de pod em um cluster do GKE. Para uma versão em PDF legível na tela, clique na imagem.
Figura 1. Como converter um bloco de CIDR de pod em um cluster do GKE. Para uma versão em PDF legível na tela, clique na imagem.

Configure os seguintes componentes com Terraform:

  • Um projeto do Cloud com um cluster VPC nativo do GKE que hospeda um aplicativo Hello World. Este aplicativo é exposto por meio de um balanceador de carga interno.
  • Uma sub-rede para o cluster do GKE.
  • Uma sub-rede que simula um bloco de CIDR no local.

Para uma discussão mais aprofundada da solução geral e dos componentes individuais, consulte NAT para um bloco de CIDR de pod do GKE.

Neste tutorial, presume-se que você esteja familiarizado com o seguinte:

  • Comandos sysadmin do Linux
  • GKE
  • Compute Engine
  • NAT
  • Terraform

Objetivos

Com Terraform, implante o seguinte:

  • Um projeto com um cluster VPC nativo do GKE
  • Uma sub-rede para o cluster do GKE
  • Uma sub-rede que simula um bloco de CIDR no local
  • Um aplicativo Hello World
  • Um balanceador de carga interno para expor o aplicativo Hello World

Com o SDK do Cloud, faça o seguinte:

  • Inspecione cada componente da solução.
  • Verifique o app Hello World.
  • Verifique a tradução do bloco de CIDR de pod da máquina simulada no local.

Custos

Neste tutorial, usamos 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 ser qualificados para uma avaliação gratuita.

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Como fazer a limpeza.

Antes de começar

Nesta seção, você prepara o Cloud Shell, configura suas variáveis de ambiente e implanta a infraestrutura de suporte.

Preparar o Cloud Shell

  1. No Console do Google Cloud, abra o Cloud Shell.

    Acessar o Cloud Shell

    Você conclui a maior parte deste tutorial pelo terminal do Cloud Shell usando o Terraform da HashiCorp e o SDK do Cloud.

  2. No Cloud Shell, clone o repositório do GitHub e altere para o diretório de trabalho local:

    git clone https://github.com/GoogleCloudPlatform/terraform-gke-nat-connectivity.git kam
    cd kam/podnat
    

    O repositório contém todos os arquivos necessários para concluir este tutorial. Para uma descrição completa de cada arquivo, consulte o arquivo README.md no repositório.

  3. Torne executáveis todos os scripts de shell:

    sudo chmod 755 *.sh
    
  4. Instale o Terraform.

  5. Inicialize o Terraform:

    terraform init
    

    A saída será assim:

    ...
    Initializing provider plugins...
    The following providers do not have any version constraints in configuration, so the latest version was installed.
    
    To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below.
    
    ∗ provider.google: version = "~> 2.5"
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work.
    
    If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
    ...
    

Definir variáveis de ambiente

  1. Defina e verifique a variável TF_VAR_org_id, substituindo your-organization-name pelo nome da organização do Google Cloud que queira usar neste tutorial:

    export TF_VAR_org_id=$(gcloud organizations list | \
        awk '/your-organization-name/ {print $2}')
    
  2. Verifique se a variável de ambiente está definida corretamente:

    echo $TF_VAR_org_id
    

    A resposta ao comando lista seu código numérico da organização e é semelhante a esta:

    ...
    123123123123
    ...
    
  3. Defina as variáveis de ambiente restantes:

    source set_variables.sh
    

    Verifique se as variáveis de ambiente estão definidas corretamente:

    env | grep TF_
    

    A saída será assim:

    ...
    TF_VAR_zone=us-west1-b
    TF_VAR_cluster_password=ThanksForAllTheFish
    TF_VAR_node_cidr=10.32.1.0/24
    TF_VAR_region=us-west1
    TF_VAR_billing_account=QQQQQQ-XAAAAA-E87690
    TF_VAR_cluster_cidr=192.168.1.0/24
    TF_VAR_org_id=406999999999
    TF_VAR_ilb_ip=10.32.1.49
    TF_VAR_isolated_vpc_pid=ivpc-pid--999999999
    TF_VAR_gcp_user=user@example
    TF_VAR_on_prem_cidr=10.32.2.0/24
    TF_VAR_cluster_username=dolphins
    TF_VAR_pod_cidr=172.16.0.0/16
    ...
    
  4. Crie um arquivo de variável de ambiente:

    env | grep TF_ | sed 's/^/export /' > TF_ENV_VARS
    

    Essa cadeia de comandos redireciona as variáveis de ambiente que você criou para um arquivo chamado TF_ENV_VARS. Cada variável é precedida pelo comando export. É possível usar esse arquivo para redefinir as variáveis de ambiente caso a sessão do Cloud Shell seja encerrada. Essas variáveis são usadas pelos scripts do Terraform e Cloud Shell e pelas ferramentas de linha de comando gcloud.

    Se você precisar reinicializar as variáveis posteriormente, execute o seguinte comando a partir do diretório no qual está o arquivo:

    source TF_ENV_VARS
    

Implantar infraestrutura de suporte

  • No Cloud Shell, implante a infraestrutura de suporte do Terraform:

    terraform apply
    

    O Terraform solicita a confirmação antes de fazer qualquer alteração. Responda yes para aplicar qualquer configuração.

    O comando terraform apply instrui o Terraform a implantar todos os componentes da solução. Para entender melhor como a infraestrutura é declarativamente definida, leia os manifestos do Terraform, ou seja, os arquivos com a extensão .tf.

Como inspecionar a infraestrutura de suporte

Agora, use as ferramentas de linha de comando gcloud para visualizar e verificar a infraestrutura que o Terraform criou. A verificação envolve a execução de um comando para ver se o recurso responde e foi criado corretamente.

Verificar os projetos

  1. No Cloud Shell, liste o projeto:

    gcloud projects list | grep ivpc-pid
    

    A saída será assim:

    ...
    isolated-vpc-pid       isolated-vpc-pname        777999333962
    ...
    
  2. Listar o status da API:

    gcloud services list --project=$TF_VAR_isolated_vpc_pid \
        | grep -E "compute|container"
    

    A saída será assim:

    ...
    compute.googleapis.com            Compute Engine API
    container.googleapis.com          Google Kubernetes Engine API
    ...
    

Verificar as redes e sub-redes

  • No Cloud Shell, verifique as redes e sub-redes:

    gcloud compute networks describe ivpc \
        --project=$TF_VAR_isolated_vpc_pid
    gcloud compute networks subnets describe node-cidr \
        --project=$TF_VAR_isolated_vpc_pid \
        --region=$TF_VAR_region
    gcloud compute networks subnets describe simulated-on-prem \
      --project=$TF_VAR_isolated_vpc_pid \
      --region=$TF_VAR_region
    

    A saída será assim:

    ...
    kind: compute#network
    name: ivpc
    routingConfig:
      routingMode: GLOBAL
    ...
    subnetworks:
    ‐ https://www.googleapis.com/compute/v1/projects/ivpc-pid--695116665/regions/us-west1/subnetworks/node-cidr
    x_gcloud_bgp_routing_mode: GLOBAL
    ...
    gatewayAddress: 10.32.1.1
    ...
    ipCidrRange: 10.32.1.0/24
    kind: compute#subnetwork
    name: node-cidr
    ...
    secondaryIpRanges:
    ‐ ipCidrRange: 172.16.0.0/16
      rangeName: pod-cidr
    ...
    subnetworks:
    ‐ https://www.googleapis.com/compute/v1/projects/ivpc-pid--695116665/regions/us-west1/subnetworks/simulated-on-prem
    x_gcloud_bgp_routing_mode: GLOBAL
    ...
    gatewayAddress: 10.32.2.1
    ...
    ipCidrRange: 10.32.2.0/24
    kind: compute#subnetwork
    name: simulated-on-prem
    ...
    

Verificar as regras de firewall

  • No Cloud Shell, verifique as regras de firewall na VPC isolada:

    gcloud compute firewall-rules list --project=$TF_VAR_isolated_vpc_pid
    

    A saída será assim:

    ...
    NAME                  NETWORK           DIRECTION  PRIORITY  ALLOW  DENY  DISABLED
    allow-rfc1918-in-fwr  isolated-vpc-net  INGRESS    1000      all          False
    allow-ssh-in-fwr      isolated-vpc-net  INGRESS    1000      22           False
    ...
    

Verificar as máquinas virtuais

  • No Cloud Shell, verifique as máquinas virtuais:

    gcloud compute instances list --project=$TF_VAR_isolated_vpc_pid
    

    A saída será assim:

    ...
    NAME                                     ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
    gke-cluster1-default-pool-fc9ba891-4xhj  us-west1-b  n1-standard-1               10.32.1.4    34.83.33.188    RUNNING
    gke-cluster1-default-pool-fc9ba891-d0bd  us-west1-b  n1-standard-1               10.32.1.3    34.83.48.81     RUNNING
    gke-cluster1-default-pool-fc9ba891-xspg  us-west1-b  n1-standard-1               10.32.1.2    35.247.62.159   RUNNING
    simulated-on-prem-host                   us-west1-b  n1-standard-1               10.32.2.2    35.227.173.106  RUNNING
    ...
    

Verificar o cluster do GKE e seus recursos

  1. No Cloud Shell, consiga as credenciais do cluster:

    gcloud container clusters get-credentials cluster1 \
        --project=$TF_VAR_isolated_vpc_pid \
        --zone $TF_VAR_zone
    

    A saída será assim:

    ...
    Fetching cluster endpoint and auth data.
    kubeconfig entry generated for cluster1.
    ...
    
  2. Verifique o cluster:

    gcloud container clusters list \
        --project=$TF_VAR_isolated_vpc_pid \
        --zone=$TF_VAR_zone
    

    A saída será assim:

    ...
    NAME     LOCATION    MASTER_VERSION MASTER_IP   MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
    cluster1 us-west1-b  1.11.8-gke.6   192.0.2.58  n1-standard-1  1.11.8-gke.6  3          RUNNING
    ...
    
  3. Verifique o aplicativo Hello World:

    kubectl get deployment my-app
    

    A saída será assim:

    ...
    NAME     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    my-app   3         3         3            3           118m
    ...
    
  4. Verifique o serviço do balanceador de carga interno:

    kubectl get service hello-server
    

    A saída será assim:

    ...
    NAME           TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
    hello-server   LoadBalancer   10.32.11.49   <pending>     8080:30635/TCP   3m
    ...
    

Como verificar a solução

Para verificar a solução, verifique o seguinte:

  • O recurso ip-masq-agent
  • Se o aplicativo Hello World está acessível externamente
  • O NAT do CIDR de pod

Verificar o recurso ip-masq-agent

  1. No Cloud Shell, consiga um nome de node:

    export NODE_NAME=$(kubectl get nodes | awk '/gke/ {print $1}' | head -n 1)
    
  2. Use SSH para se conectar a um nó de cluster:

    gcloud compute ssh $NODE_NAME \
        --project=$TF_VAR_isolated_vpc_pid \
        --zone=$TF_VAR_zone
    
  3. Verifique a configuração ip-masq-agent:

    sudo iptables -t nat -L
    

    A saída será assim:

    ...
    Chain IP-MASQ (2 references)
    target      prot opt source               destination
    RETURN      all  --  anywhere             169.254.0.0/16       /* ip-masq-agent: local traffic is not subject to MASQUERADE */
    RETURN      all  --  anywhere             10.32.1.0/24         /* ip-masq-agent: local traffic is not subject to MASQUERADE */
    RETURN      all  --  anywhere             172.16.0.0/16        /* ip-masq-agent: local traffic is not subject to MASQUERADE */
    RETURN      all  --  anywhere             192.168.1.0/24       /* ip-masq-agent: local traffic is not subject to MASQUERADE */
    MASQUERADE  all  --  anywhere             anywhere             /* ip-masq-agent: outbound traffic is subject to MASQUERADE (must be last in chain) */
    ...
    
  4. Saia da sessão SSH.

    exit
    

Verificar se o aplicativo Hello World está acessível externamente

  1. Use SSH para se conectar à VM simulada no local:

    gcloud compute ssh simulated-on-prem-host \
        --project=$TF_VAR_isolated_vpc_pid \
        --zone=$TF_VAR_zone
    
  2. Verifique o aplicativo Hello World:

    curl http://10.32.1.49:8080
    

    A saída será assim:

    ...
    Hello, world!
    Version: 1.0.0
    Hostname: my-app-77748bfbd8-nqwl2
    ...
    

Verificar o NAT do CIDR de pod

  1. Na VM simulada no local, execute tcpdump:

    sudo tcpdump -n icmp
    

    A saída será assim:

    ...
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
    ...
    

    Este comando inicia o utilitário tcpdump para capturar os pacotes que atravessam o gateway da VPC isolada. O utilitário só captura pacotes que contêm o endereço IP do balanceador de carga interno criado pelo serviço do GKE.

  2. No Console do Cloud, abra um novo terminal do Cloud Shell.

    Acessar o Cloud Shell

  3. No novo terminal, defina variáveis de ambiente alterando para o diretório do repositório Git e inserindo o seguinte comando:

    source TF_ENV_VARS
    
  4. Consiga as credenciais do cluster:

    gcloud container clusters get-credentials cluster1 \
        --project=$TF_VAR_isolated_vpc_pid \
        --zone $TF_VAR_zone
    
  5. Consiga o nome do pod:

    export POD_NAME=$(kubectl get pods | awk '/my-app/ {print $1}' | head -n 1)
    
  6. Conecte-se ao shell do pod:

    kubectl exec -it $POD_NAME -- /bin/sh
    
  7. No terminal Cloud Shell original, dê um ping na VM simulada no local:

    ping 10.32.2.2
    

    No terminal original, a resposta será assim:

    ...
    
    05:43:40.669371 IP 10.32.1.3 > 10.32.2.2: ICMP echo request, id 3328, seq 0, length 64
    05:43:40.669460 IP 10.32.2.2 > 10.32.1.3: ICMP echo reply, id 3328, seq 0, length 64
    ...
    

    Observe que o endereço IP de origem é do bloco de CIDR do nó 10.32.1.0/24. O bloco de CIDR do pod 10.32.2.0/24 foi convertido atrás do endereço do nó. Pressione Control+C para interromper o ping e sair de todas as sessões do terminal.

Como fazer a limpeza

Destruir a infraestrutura

  1. No primeiro terminal do Cloud Shell, saia da sessão SSH para o gateway da VPC isolada digitando exit.
  2. Destrua todos os componentes do tutorial:

    terraform destroy
    

    O Terraform solicita a confirmação antes de fazer a alteração. Responda yes para destruir a configuração.

    É possível ver o seguinte erro do Terraform:

    ...
    ∗ google_compute_network.ivpc (destroy): 1 error(s) occurred:
    ∗ google_compute_network.ivpc: Error waiting for Deleting Network: The network resource 'projects/ivpc-pid--1058675427/global/networks/isolated-vpc-net' is already being used by 'projects/ivpc-pid--1058675427/global/firewalls/k8s-05693142c93de80e-node-hc'
    ...
    

    Este erro ocorre quando o comando tenta destruir a rede VPC isolada antes de destruir as regras de firewall do GKE. Execute o seguinte script para remover as regras de firewall não padrão da VPC isolada:

    ./k8-fwr.sh
    

    A resposta mostra quais regras de firewall serão removidas.

  3. Revise as regras e, quando solicitado, digite yes.

  4. No primeiro terminal do Cloud Shell, emita novamente o seguinte comando:

    terraform destroy
    

    O Terraform solicita a confirmação antes de fazer a alteração. Responda yes para destruir a configuração.

  5. No terminal do Cloud Shell original, emita o seguinte comando:

    cd ../..
    rm -rf kam
    

A seguir