Implantar no Compute Engine


Este guia explica como executar implantações azul-verde sem tempo de inatividade Grupos gerenciados de instâncias (MIGs) do Compute Engine usando o Cloud Build e o Terraform.

O Cloud Build permite automatizar vários processos para desenvolvedores, incluindo criar e implantar aplicativos em vários ambientes de execução do Google Cloud como o Compute Engine, Google Kubernetes Engine, GKE Enterprise, e funções do Cloud Run.

Os MIGs do Compute Engine permitem operar aplicativos em várias máquinas virtuais (VMs) idênticas. É possível tornar as cargas de trabalho escalonáveis e altamente disponíveis aproveitando serviços de MIG automatizados, como escalonamento automático, recuperação automática, implantação regional (várias zonas) e atualização automática. Como usar a implantação contínua azul-verde você vai aprender a transferir gradualmente o tráfego de usuários de um MIG (azul) para outro MIG (verde), ambos em execução na produção.

Visão geral do design

O diagrama a seguir mostra o modelo de implantação azul-verde usado pelo código descrito neste documento:

Modelo azul-verde

Em um nível alto, esse modelo inclui os seguintes componentes:

  • Dois pools de VMs do Compute Engine: azul e verde.
  • Três balanceadores de carga HTTP(S) externos:
    • Um balanceador de carga azul/verde, que roteia o tráfego de usuários finais para o pool azul ou verde de instâncias de VM.
    • Um balanceador de carga Blue que roteia o tráfego de engenheiros de QA e desenvolvedores para o pool de instâncias de VM Blue.
    • Um balanceador de carga verde que encaminha o tráfego de engenheiros de QA e desenvolvedores para o pool de instâncias verdes.
  • Dois conjuntos de usuários:
    • Os usuários finais que têm acesso ao balanceador de carga azul/verde, que aponta ao pool de instâncias azul ou verde.
    • Engenheiros e desenvolvedores de controle de qualidade que precisam de acesso aos dois conjuntos de pools para para fins de desenvolvimento e teste. Eles podem acessar os ícones Azul e balanceadores de carga verdes, que os encaminham para o pool de instâncias azul e o Pool de instâncias verde, respectivamente.

os pools de VMs azul e verde são implementados como MIGs do Compute Engine. os endereços IP externo são roteados para as VMs no MIG usando HTTP(s) externos balanceadores de carga de aplicativo externos. O exemplo de código descrito neste documento usa o Terraform para configurar essa infraestrutura.

O diagrama a seguir ilustra as operações do desenvolvedor que ocorrem na implantação:

Fluxo de operações do desenvolvedor

No diagrama acima, as setas vermelhas representam o fluxo de bootstrapping ocorre quando você configura a infraestrutura de implantação pela primeira vez, e o as setas azuis representam o fluxo do GitOps que ocorre durante cada implantação.

Para configurar essa infraestrutura, execute um script de configuração que inicia o processo de inicialização e configura os componentes para o fluxo do GitOps.

O script de configuração executa um pipeline do Cloud Build que realiza a seguintes operações:

  • Cria um repositório no Cloud Source Repositories chamado copy-of-gcp-mig-simple e copia o código-fonte do repositório de exemplo do GitHub para o repositório no Cloud Source Repositories.
  • cria dois gatilhos do Cloud Build chamados apply e destroy.

O acionador apply é anexado a um arquivo do Terraform chamado main.tfvars nos repositórios de origem do Cloud. Esse arquivo contém as variáveis do Terraform que representam os balanceadores de carga azuis e verdes.

Para configurar a implantação, atualize as variáveis no arquivo main.tfvars. O gatilho apply executa um pipeline do Cloud Build que executa tf_apply e realiza as seguintes operações:

  • Cria dois MIGs do Compute Engine (um para verde e outro para azul), quatro Instâncias de VM do Compute Engine (duas para o MIG verde e duas para o azul os três balanceadores de carga (azul, verde e divisor) e os três endereços IP públicos.
  • Mostra os endereços IP que podem ser usados para conferir os aplicativos implantados nas instâncias azul e verde.

O acionador de destruição é acionado manualmente para excluir todos os recursos criados pelo acionador de aplicação.

Objetivos

  • Use o Cloud Build e o Terraform para configurar balanceadores de carga HTTP(S) externos com back-ends de grupo de instâncias de VM do Compute Engine.

  • Executar implantações azul-verde nas instâncias de VM.

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. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Install the Google Cloud CLI.
  7. To initialize the gcloud CLI, run the following command:

    gcloud init
  8. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  9. Make sure that billing is enabled for your Google Cloud project.

Testar

  1. Execute o script de configuração do repositório de exemplo de código do Google:

    bash <(curl https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-build-samples/main/mig-blue-green/setup.sh)
    
  2. Quando o script de configuração pedir o consentimento do usuário, digite sim.

    O script termina de ser executado em alguns segundos.

  3. No console do Google Cloud, abra a página Histórico de build do Cloud Build:

    Abrir a página "Histórico de builds"

  4. Clique no build mais recente.

    A página Detalhes do build aparece, mostrando um pipeline do Cloud Build com três etapas de build: a primeira cria um repositório no Cloud Source Repositories, a segunda clona o conteúdo do repositório de exemplo no GitHub para o Cloud Source Repositories, e a terceira adiciona dois gatilhos de build.

  5. Abra o Cloud Source Repositories:

    Abrir o Cloud Source Repositories

  6. Na lista de repositórios, clique em copy-of-gcp-mig-simple.

    Na guia Histórico, na parte inferior da página, você verá um commit com a descrição A copy of https://github.com/GoogleCloudPlatform/cloud-build-samples.git feita pelo Cloud Build para criar um repositório chamado copy-of-gcp-mig-simple.

  7. Abra a página Gatilhos do Cloud Build:

    Abrir a página "Gatilhos"

  8. Você vai encontrar dois gatilhos de build chamados apply e destroy. O gatilho apply está anexado ao arquivo infra/main.tfvars na ramificação main. Este gatilho é executado sempre que o arquivo é atualizado. O acionador destroy é manual.

  9. Para iniciar o processo de implantação, atualize o arquivo infra/main.tfvars:

    1. Na janela do terminal, crie e navegue até uma pasta chamada deploy-compute-engine:

      mkdir ~/deploy-compute-engine
      cd ~/deploy-compute-engine
      
    2. Clone o repositório copy-of-gcp-mig-simple:

      gcloud source repos clone copy-of-mig-blue-green
      
    3. Navegue até o diretório clonado:

      cd ./copy-of-mig-blue-green
      
    4. Atualize infra/main.tfvars para substituir o azul por verde:

      sed -i'' -e 's/blue/green/g' infra/main.tfvars
      
    5. Adicione o arquivo atualizado:

      git add .
      
    6. Faça a confirmação do arquivo:

      git commit -m "Promote green"
      
    7. Envie o arquivo:

      git push
      

      Fazer mudanças no infra/main.tfvars aciona a execução do apply. que inicia a implantação.

  10. Abra o Cloud Source Repositories:

    Abrir o Cloud Source Repositories

  11. Na lista de repositórios, clique em copy-of-gcp-mig-simple.

    O commit com a descrição Promote green vai aparecer na guia History, na parte de baixo da página.

  12. Para conferir a execução do gatilho apply, abra a página Histórico da build no console do Google Cloud:

    Abrir a página "Histórico de criações"

  13. Clique no primeiro build para abrir a página Detalhes do build.

    Você vai notar o pipeline do gatilho apply com duas etapas de build. A primeira etapa de build executa o Terraform apply para criar o Compute Engine e os recursos de balanceamento de carga para a implantação. A segunda etapa do build mostra o endereço IP onde você vê o aplicativo em execução.

  14. Abra o endereço IP correspondente ao MIG verde em um navegador. Você vai ver uma captura de tela semelhante a esta mostrando a implantação:

    Implantação

  15. Acesse a página Grupo de instâncias do Compute Engine para ver as colunas Azul e Grupos de instâncias verdes:

    Abrir a página "Grupo de instâncias"

  16. Abra a página Instâncias de VM para ver as quatro instâncias:

    Abrir a página "Instâncias de VM"

  17. Abra a página Endereços IP externos para conferir os três balanceadores de carga:

    Abrir a página "Endereços IP externos"

Noções básicas sobre o código

O código-fonte desse exemplo de código inclui:

  • Código-fonte relacionado ao script de configuração.
  • Código-fonte relacionado aos pipelines do Cloud Build.
  • Código-fonte relacionado aos modelos do Terraform.

Script de configuração

setup.sh é o script de configuração que executa o processo de inicialização e cria os componentes para a implantação azul-verde. O script executa o seguinte operações:

  • Ativa o Cloud Build, o Resource Manager Compute Engine e Cloud Source Repositories.
  • Concede o papel roles/editor do IAM à conta de serviço do Cloud Build no seu projeto. Esse papel é necessário para que o Cloud Build crie e configure os componentes necessários do GitOps para a implantação.
  • Concede o papel roles/source.admin do IAM ao conta de serviço do Cloud Build no projeto. Essa função é necessária para que a conta de serviço do Cloud Build crie os repositórios do Cloud Source no seu projeto e clone o conteúdo do repositório do GitHub de exemplo para os repositórios do Cloud Source.
  • Gera um pipeline do Cloud Build chamado bootstrap.cloudbuild.yaml inline, que:

    • Cria um novo repositório no Cloud Source Repositories.
    • Copia o código-fonte do repositório do GitHub de exemplo para o novo repositório no Cloud Source Repositories.
    • Cria os gatilhos de aplicação e destruição de build.
set -e

BLUE='\033[1;34m'
RED='\033[1;31m'
GREEN='\033[1;32m'
NC='\033[0m'

echo -e "\n${GREEN}######################################################"
echo -e "#                                                    #"
echo -e "#  Zero-Downtime Blue/Green VM Deployments Using     #"
echo -e "#  Managed Instance Groups, Cloud Build & Terraform  #"
echo -e "#                                                    #"
echo -e "######################################################${NC}\n"

echo -e "\nSTARTED ${GREEN}setup.sh:${NC}"

echo -e "\nIt's ${RED}safe to re-run${NC} this script to ${RED}recreate${NC} all resources.\n"
echo "> Checking GCP CLI tool is installed"
gcloud --version > /dev/null 2>&1

readonly EXPLICIT_PROJECT_ID="$1"
readonly EXPLICIT_CONSENT="$2"

if [ -z "$EXPLICIT_PROJECT_ID" ]; then
    echo "> No explicit project id provided, trying to infer"
    PROJECT_ID="$(gcloud config get-value project)"
else
    PROJECT_ID="$EXPLICIT_PROJECT_ID"
fi

if [ -z "$PROJECT_ID" ]; then
    echo "ERROR: GCP project id was not provided as parameter and could not be inferred"
    exit 1
else
    readonly PROJECT_NUM="$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')"
    if [ -z "$PROJECT_NUM" ]; then
        echo "ERROR: GCP project number could not be determined"
        exit 1
    fi
    echo -e "\nYou are about to:"
    echo -e "  * modify project ${RED}${PROJECT_ID}/${PROJECT_NUM}${NC}"
    echo -e "  * ${RED}enable${NC} various GCP APIs"
    echo -e "  * make Cloud Build ${RED}editor${NC} of your project"
    echo -e "  * ${RED}execute${NC} Cloud Builds and Terraform plans to create"
    echo -e "  * ${RED}4 VMs${NC}, ${RED}3 load balancers${NC}, ${RED}3 public IP addresses${NC}"
    echo -e "  * incur ${RED}charges${NC} in your billing account as a result\n"
fi

if [ "$EXPLICIT_CONSENT" == "yes" ]; then
  echo "Proceeding under explicit consent"
  readonly CONSENT="$EXPLICIT_CONSENT"
else
    echo -e "Enter ${BLUE}'yes'${NC} if you want to proceed:"
    read CONSENT
fi

if [ "$CONSENT" != "yes" ]; then
    echo -e "\nERROR: Aborted by user"
    exit 1
else
    echo -e "\n......................................................"
    echo -e "\n> Received user consent"
fi

#
# Executes action with one randomly delayed retry.
#
function do_with_retry {
    COMMAND="$@"
    echo "Trying $COMMAND"
    (eval $COMMAND && echo "Success on first try") || ( \
        echo "Waiting few seconds to retry" &&
        sleep 10 && \
        echo "Retrying $COMMAND" && \
        eval $COMMAND \
    )
}

echo "> Enabling required APIs"
# Some of these can be enabled later with Terraform, but I personally
# prefer to do all API enablement in one place with gcloud.
gcloud services enable \
    --project=$PROJECT_ID \
    cloudbuild.googleapis.com \
    cloudresourcemanager.googleapis.com \
    compute.googleapis.com \
    sourcerepo.googleapis.com \
    --no-user-output-enabled \
    --quiet

echo "> Adding Cloud Build to roles/editor"
gcloud projects add-iam-policy-binding \
    "$PROJECT_ID" \
    --member="serviceAccount:$PROJECT_NUM@cloudbuild.gserviceaccount.com" \
    --role='roles/editor' \
    --condition=None \
    --no-user-output-enabled \
    --quiet

echo "> Adding Cloud Build to roles/source.admin"
gcloud projects add-iam-policy-binding \
    "$PROJECT_ID" \
    --member="serviceAccount:$PROJECT_NUM@cloudbuild.gserviceaccount.com" \
    --condition=None \
    --role='roles/source.admin' \
    --no-user-output-enabled \
    --quiet

echo "> Configuring bootstrap job"
rm -rf "./bootstrap.cloudbuild.yaml"
cat <<'EOT_BOOT' > "./bootstrap.cloudbuild.yaml"
tags:
- "mig-blue-green-bootstrapping"
steps:
- id: create_new_cloud_source_repo
  name: "gcr.io/cloud-builders/gcloud"
  script: |
    #!/bin/bash
    set -e

    echo "(Re)Creating source code repository"

    gcloud source repos delete \
        "copy-of-mig-blue-green" \
        --quiet || true

    gcloud source repos create \
        "copy-of-mig-blue-green" \
        --quiet

- id: copy_demo_source_into_new_cloud_source_repo
  name: "gcr.io/cloud-builders/gcloud"
  env:
    - "PROJECT_ID=$PROJECT_ID"
    - "PROJECT_NUMBER=$PROJECT_NUMBER"
  script: |
    #!/bin/bash
    set -e

    readonly GIT_REPO="https://github.com/GoogleCloudPlatform/cloud-build-samples.git"

    echo "Cloning demo source repo"
    mkdir /workspace/from/
    cd /workspace/from/
    git clone $GIT_REPO ./original
    cd ./original

    echo "Cloning new empty repo"
    mkdir /workspace/to/
    cd /workspace/to/
    gcloud source repos clone \
        "copy-of-mig-blue-green"
    cd ./copy-of-mig-blue-green

    echo "Making a copy"
    cp -r /workspace/from/original/mig-blue-green/* ./

    echo "Setting git identity"
    git config user.email \
        "$PROJECT_NUMBER@cloudbuild.gserviceaccount.com"
    git config user.name \
        "Cloud Build"

    echo "Commit & push"
    git add .
    git commit \
        -m "A copy of $GIT_REPO"
    git push

- id: add_pipeline_triggers
  name: "gcr.io/cloud-builders/gcloud"
  env:
    - "PROJECT_ID=$PROJECT_ID"
  script: |
    #!/bin/bash
    set -e

    echo "(Re)Creating destroy trigger"
    gcloud builds triggers delete "destroy" --quiet || true
    gcloud builds triggers create manual \
        --name="destroy" \
        --repo="https://source.developers.google.com/p/$PROJECT_ID/r/copy-of-mig-blue-green" \
        --branch="master" \
        --build-config="pipelines/destroy.cloudbuild.yaml" \
        --repo-type=CLOUD_SOURCE_REPOSITORIES \
        --quiet

    echo "(Re)Creating apply trigger"
    gcloud builds triggers delete "apply" --quiet || true
    gcloud builds triggers create cloud-source-repositories \
        --name="apply" \
        --repo="copy-of-mig-blue-green" \
        --branch-pattern="master" \
        --build-config="pipelines/apply.cloudbuild.yaml" \
        --included-files="infra/main.tfvars" \
        --quiet

EOT_BOOT

echo "> Waiting API enablement propagation"
do_with_retry "(gcloud builds list --project "$PROJECT_ID" --quiet && gcloud compute instances list --project "$PROJECT_ID" --quiet && gcloud source repos list --project "$PROJECT_ID" --quiet) > /dev/null 2>&1" > /dev/null 2>&1

echo "> Executing bootstrap job"
gcloud beta builds submit \
    --project "$PROJECT_ID" \
    --config ./bootstrap.cloudbuild.yaml \
    --no-source \
    --no-user-output-enabled \
    --quiet
rm ./bootstrap.cloudbuild.yaml

echo -e "\n${GREEN}All done. Now you can:${NC}"
echo -e "  * manually run 'apply' and 'destroy' triggers to manage deployment lifecycle"
echo -e "  * commit change to 'infra/main.tfvars' and see 'apply' pipeline trigger automatically"

echo -e "\n${GREEN}Few key links:${NC}"
echo -e "  * Dashboard: https://console.cloud.google.com/home/dashboard?project=$PROJECT_ID"
echo -e "  * Repo: https://source.cloud.google.com/$PROJECT_ID/copy-of-mig-blue-green"
echo -e "  * Cloud Build Triggers: https://console.cloud.google.com/cloud-build/triggers;region=global?project=$PROJECT_ID"
echo -e "  * Cloud Build History: https://console.cloud.google.com/cloud-build/builds?project=$PROJECT_ID"

echo -e "\n............................."

echo -e "\n${GREEN}COMPLETED!${NC}"

Pipelines do Cloud Build

apply.cloudbuild.yaml e destroy.cloudbuild.yaml são os arquivos de configuração do Cloud Build que o script de configuração usa para configurar os recursos do fluxo do GitOps. O apply.cloudbuild.yaml contém duas etapas de build:

  • a etapa de build tf_apply build que chama a função; tf_install_in_cloud_build_step, que instala o Terraform. tf_apply que cria os recursos usados no fluxo do GitOps. As funções tf_install_in_cloud_build_step e tf_apply são definidos em bash_utils.sh e a etapa de build usa o comando source para chamar para resolvê-los com rapidez.
  • Etapa de build describe_deployment que chama a função describe_deployment, que imprime os endereços IP dos balanceadores de carga.

destroy.cloudbuild.yaml chama tf_destroy, que exclui todos os recursos criado por tf_apply.

As funções tf_install_in_cloud_build_step, tf_apply, describe_deployment e tf_destroy são definidos no arquivo bash_utils.sh. Os arquivos de configuração do build usam o comando source para chamar as funções.

steps:
  - id: run-terraform-apply
    name: "gcr.io/cloud-builders/gcloud"
    env:
      - "PROJECT_ID=$PROJECT_ID"
    script: |
      #!/bin/bash
      set -e
      source /workspace/lib/bash_utils.sh
      tf_install_in_cloud_build_step
      tf_apply

  - id: describe-deployment
    name: "gcr.io/cloud-builders/gcloud"
    env:
      - "PROJECT_ID=$PROJECT_ID"
    script: |
      #!/bin/bash
      set -e
      source /workspace/lib/bash_utils.sh
      describe_deployment

tags:
  - "mig-blue-green-apply"
steps:
  - id: run-terraform-destroy
    name: "gcr.io/cloud-builders/gcloud"
    env:
      - "PROJECT_ID=$PROJECT_ID"
    script: |
      #!/bin/bash
      set -e
      source /workspace/lib/bash_utils.sh
      tf_install_in_cloud_build_step
      tf_destroy

tags:
  - "mig-blue-green-destroy"

O código a seguir mostra a função tf_install_in_cloud_build_step, que é definido em bash_utils.sh. Os arquivos de configuração de build chamam essa função para instalar o Terraform em tempo real. Ele cria um bucket do Cloud Storage para para registrar o status do Terraform.

function tf_install_in_cloud_build_step {
    echo "Installing deps"
    apt update
    apt install \
        unzip \
        wget \
        -y

    echo "Manually installing Terraform"
    wget https://releases.hashicorp.com/terraform/1.3.4/terraform_1.3.4_linux_386.zip
    unzip -q terraform_1.3.4_linux_386.zip
    mv ./terraform /usr/bin/
    rm -rf terraform_1.3.4_linux_386.zip

    echo "Verifying installation"
    terraform -v

    echo "Creating Terraform state storage bucket $BUCKET_NAME"
    gcloud storage buckets create \
        "gs://$BUCKET_NAME" || echo "Already exists..."

    echo "Configure Terraform provider and state bucket"
cat <<EOT_PROVIDER_TF > "/workspace/infra/provider.tf"
terraform {
  required_version = ">= 0.13"
  backend "gcs" {
    bucket = "$BUCKET_NAME"
  }
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 3.77, < 5.0"
    }
  }
}
EOT_PROVIDER_TF

    echo "$(cat /workspace/infra/provider.tf)"
}

O snippet de código a seguir mostra a função tf_apply definida em bash_utils.sh. Primeiro, ele chama terraform init, que carrega todos os módulos e bibliotecas personalizadas e, em seguida, executa terraform apply para carregar as variáveis da o arquivo main.tfvars.

function tf_apply {
    echo "Running Terraform init"
    terraform \
        -chdir="$TF_CHDIR" \
        init

    echo "Running Terraform apply"
    terraform \
        -chdir="$TF_CHDIR" \
        apply \
        -auto-approve \
        -var project="$PROJECT_ID" \
        -var-file="main.tfvars"
}

O snippet de código a seguir mostra a função describe_deployment, que é definido em bash_utils.sh. Ele usa gcloud compute addresses describe para buscar os endereços IP dos balanceadores de carga usando o nome e os imprime.

function describe_deployment {
    NS="ns1-"
    echo -e "Deployment configuration:\n$(cat infra/main.tfvars)"
    echo -e \
      "Here is how to connect to:" \
      "\n\t* active color MIG: http://$(gcloud compute addresses describe ${NS}splitter-address-name --region=us-west1 --format='value(address)')/" \
      "\n\t* blue color MIG: http://$(gcloud compute addresses describe ${NS}blue-address-name --region=us-west1 --format='value(address)')/" \
      "\n\t* green color MIG: http://$(gcloud compute addresses describe ${NS}green-address-name --region=us-west1 --format='value(address)')/"
    echo "Good luck!"
}

O snippet de código a seguir mostra a função tf_destroy, que é definida em bash_utils.sh. Ele chama terraform init, que carrega todos os módulos e bibliotecas personalizadas e, em seguida, executa terraform destroy, que descarrega as variáveis do Terraform.

function tf_destroy {
    echo "Running Terraform init"
    terraform \
        -chdir="$TF_CHDIR" \
        init

    echo "Running Terraform destroy"
    terraform \
        -chdir="$TF_CHDIR" \
        destroy \
        -auto-approve \
        -var project="$PROJECT_ID" \
        -var-file="main.tfvars"
}

Modelos do Terraform

Todos os arquivos e variáveis de configuração do Terraform estão na pasta copy-of-gcp-mig-simple/infra/.

  • main.tf: é o arquivo de configuração do Terraform
  • main.tfvars: este arquivo define as variáveis do Terraform.
  • mig/ e splitter/: essas pastas contêm os módulos que definem o balanceadores de carga de aplicativo externos. A pasta mig/ contém o arquivo de configuração do Terraform que define o MIG para os balanceadores de carga azuis e verdes. As APIs Azul e os MIGs verdes são idênticos, então eles são definidos uma vez e para os objetos azul e verde. O arquivo de configuração do Terraform para o balanceador de carga do divisor está na pasta splitter/.

O snippet de código abaixo mostra o conteúdo de infra/main.tfvars. Ela contém três variáveis: duas que determinam a versão do aplicativo a ser implantada ao pool Azul e ao Verde e uma variável para a cor ativa: Azul ou verde. As alterações nesse arquivo acionam a implantação.

MIG_VER_BLUE     = "v1"
MIG_VER_GREEN    = "v1"
MIG_ACTIVE_COLOR = "blue"

Confira a seguir um snippet de código de infra/main.tf. Neste snippet:

  • Uma variável é definida para o projeto do Google Cloud.
  • O Google está definido como o provedor do Terraform.
  • Uma variável é definida para o namespace. Todos os objetos criados pelo Terraform têm o prefixo dessa variável para que várias versões do aplicativo possam ser implantadas no mesmo projeto e os nomes dos objetos não colidam entre si.
  • As variáveis MIG_VER_BLUE, MIG_VER_BLUE e MIG_ACTIVE_COLOR são as vinculações para as variáveis no arquivo infra/main.tfvars.
variable "project" {
  type        = string
  description = "GCP project we are working in."
}

provider "google" {
  project = var.project
  region  = "us-west1"
  zone    = "us-west1-a"
}

variable "ns" {
  type        = string
  default     = "ns1-"
  description = "The namespace used for all resources in this plan."
}

variable "MIG_VER_BLUE" {
  type        = string
  description = "Version tag for 'blue' deployment."
}

variable "MIG_VER_GREEN" {
  type        = string
  description = "Version tag for 'green' deployment."
}

variable "MIG_ACTIVE_COLOR" {
  type        = string
  description = "Active color (blue | green)."
}

O snippet de código a seguir de infra/main.tf mostra a instanciação do módulo de divisão. Esse módulo recebe a cor ativa para que o balanceador de carga do divisor saiba qual MIG implantar o aplicativo.

module "splitter-lb" {
  source               = "./splitter"
  project              = var.project
  ns                   = "${var.ns}splitter-"
  active_color         = var.MIG_ACTIVE_COLOR
  instance_group_blue  = module.blue.google_compute_instance_group_manager_default.instance_group
  instance_group_green = module.green.google_compute_instance_group_manager_default.instance_group
}

O snippet de código abaixo de infra/main.tf define dois módulos idênticos para MIGs azuis e verdes. Ele usa a cor, a rede e a sub-rede que são definidos no módulo do divisor.

module "blue" {
  source                               = "./mig"
  project                              = var.project
  app_version                          = var.MIG_VER_BLUE
  ns                                   = var.ns
  color                                = "blue"
  google_compute_network               = module.splitter-lb.google_compute_network
  google_compute_subnetwork            = module.splitter-lb.google_compute_subnetwork_default
  google_compute_subnetwork_proxy_only = module.splitter-lb.google_compute_subnetwork_proxy_only
}

module "green" {
  source                               = "./mig"
  project                              = var.project
  app_version                          = var.MIG_VER_GREEN
  ns                                   = var.ns
  color                                = "green"
  google_compute_network               = module.splitter-lb.google_compute_network
  google_compute_subnetwork            = module.splitter-lb.google_compute_subnetwork_default
  google_compute_subnetwork_proxy_only = module.splitter-lb.google_compute_subnetwork_proxy_only
}

O arquivo splitter/main.tf define os objetos criados para o o MIG do splitter. Confira abaixo um snippet de código da splitter/main.tf que contém a lógica para alternar entre o MIG verde e azul. Ele é apoiado por o serviço google_compute_region_backend_service, que pode rotear tráfego para duas regiões de back-end: var.instance_group_blue ou var.instance_group_green. capacity_scaler define o tráfego a ser roteado.

O código a seguir encaminha 100% do tráfego para a cor especificada, mas você pode atualizar esse código para a implantação canário para encaminhar o tráfego para um subconjunto de usuários.

resource "google_compute_region_backend_service" "default" {
  name                  = local.l7-xlb-backend-service
  region                = "us-west1"
  load_balancing_scheme = "EXTERNAL_MANAGED"
  health_checks         = [google_compute_region_health_check.default.id]
  protocol              = "HTTP"
  session_affinity      = "NONE"
  timeout_sec           = 30
  backend {
    group           = var.instance_group_blue
    balancing_mode  = "UTILIZATION"
    capacity_scaler = var.active_color == "blue" ? 1 : 0
  }
  backend {
    group           = var.instance_group_green
    balancing_mode  = "UTILIZATION"
    capacity_scaler = var.active_color == "green" ? 1 : 0
  }
}

O arquivo mig/main.tf define os objetos relacionados às MIGs azuis e verdes. O snippet de código a seguir define o modelo de instância do Compute Engine usado para criar os pools de VM. Observe que o ciclo de vida da propriedade do modelo de instância está definido como create_before_destroy. Isso porque, ao atualizar a versão do pool, não é possível usar o para criar a nova versão dos pools quando ela ainda estiver sendo usada a versão anterior do pool. Mas, se a versão mais antiga do pool for destruídos antes de criar o novo modelo, haverá um período de tempo em que que as piscinas caíram. Para evitar esse cenário, definimos o ciclo de vida do Terraform como create_before_destroy para que a versão mais recente de um pool de VMs seja criada primeiro antes que a versão mais antiga seja destruída.

resource "google_compute_instance_template" "default" {
  name = local.l7-xlb-backend-template
  disk {
    auto_delete  = true
    boot         = true
    device_name  = "persistent-disk-0"
    mode         = "READ_WRITE"
    source_image = "projects/debian-cloud/global/images/family/debian-10"
    type         = "PERSISTENT"
  }
  labels = {
    managed-by-cnrm = "true"
  }
  machine_type = "n1-standard-1"
  metadata = {
    startup-script = <<EOF
    #! /bin/bash
    sudo apt-get update
    sudo apt-get install apache2 -y
    sudo a2ensite default-ssl
    sudo a2enmod ssl
    vm_hostname="$(curl -H "Metadata-Flavor:Google" \
    http://169.254.169.254/computeMetadata/v1/instance/name)"
    sudo echo "<html><body style='font-family: Arial; margin: 64px; background-color: light${var.color};'><h3>Hello, World!<br><br>version: ${var.app_version}<br>ns: ${var.ns}<br>hostname: $vm_hostname</h3></body></html>" | \
    tee /var/www/html/index.html
    sudo systemctl restart apache2
    EOF
  }
  network_interface {
    access_config {
      network_tier = "PREMIUM"
    }
    network    = var.google_compute_network.id
    subnetwork = var.google_compute_subnetwork.id
  }
  region = "us-west1"
  scheduling {
    automatic_restart   = true
    on_host_maintenance = "MIGRATE"
    provisioning_model  = "STANDARD"
  }
  tags = ["load-balanced-backend"]

  # NOTE: the name of this resource must be unique for every update;
  #       this is wy we have a app_version in the name; this way
  #       new resource has a different name vs old one and both can
  #       exists at the same time
  lifecycle {
    create_before_destroy = true
  }
}

Limpar

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

Excluir recursos individuais

  1. Exclua os recursos do Compute Engine criados pelo gatilho apply:

    1. Abra a página Gatilhos do Cloud Build:

      Abrir a página "Gatilhos"

    2. Na tabela Triggers, localize a linha correspondente ao destroy. e clique em Executar. Quando o gatilho conclui a execução, o os recursos criados pelo gatilho apply são excluídos.

  2. Exclua os recursos criados durante o inicialização executando o seguinte comando na janela do terminal:

    bash <(curl https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-build-samples/main/mig-blue-green/teardown.sh)
    

Exclua o projeto

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

A seguir