Implemente no Compute Engine


Este guia explica como fazer implementações azul/verde sem tempo de inatividade em grupos de instâncias geridos (MIGs) do Compute Engine através do Cloud Build e do Terraform.

O Cloud Build permite-lhe automatizar uma variedade de processos de programadores, incluindo a criação e a implementação de aplicações em vários Google Cloud tempos de execução como o Compute Engine, Google Kubernetes Engine, GKE Enterprise e funções do Cloud Run.

Os GIGs do Compute Engine permitem-lhe operar aplicações em várias máquinas virtuais (VMs) idênticas. Pode tornar as suas cargas de trabalho escaláveis e altamente disponíveis tirando partido dos serviços de MIG automatizados, incluindo: escalamento automático, autocura, implementação regional (várias zonas) e atualização automática. Com o modelo de implementação contínua azul/verde, vai aprender a transferir gradualmente o tráfego de utilizadores de um MIG (azul) para outro MIG (verde), ambos em execução na produção.

Vista geral do design

O diagrama seguinte mostra o modelo de implementação azul/verde usado no exemplo de código descrito neste documento:

Modelo azul/verde

A um nível elevado, este modelo inclui os seguintes componentes:

  • Dois conjuntos de VMs do Compute Engine: azul e verde.
  • Três balanceadores de carga HTTP(S) externos:
    • Um equilibrador de carga azul/verde que encaminha o tráfego dos utilizadores finais para o conjunto azul ou verde de instâncias de VM.
    • Um equilibrador de carga azul que encaminha o tráfego de engenheiros de CQ e programadores para o conjunto de instâncias de VM azul.
    • Um equilibrador de carga verde que encaminha o tráfego de engenheiros de CQ e programadores para o conjunto de instâncias verde.
  • Dois conjuntos de utilizadores:
    • Utilizadores finais que têm acesso ao equilibrador de carga azul/verde, que os direciona para o conjunto de instâncias azul ou verde.
    • Engenheiros de controlo de qualidade e programadores que precisam de acesso a ambos os conjuntos de pools para fins de desenvolvimento e testes. Podem aceder aos balanceadores de carga azuis e verdes, que os encaminham para o conjunto de instâncias azuis e o conjunto de instâncias verdes, respetivamente.

Os conjuntos de VMs azuis e verdes são implementados como MIGs do Compute Engine, e os endereços IP externos são encaminhados para as VMs no MIG através de equilibradores de carga HTTP(s) externos. O exemplo de código descrito neste documento usa o Terraform para configurar esta infraestrutura.

O diagrama seguinte ilustra as operações do programador que ocorrem na implementação:

Fluxo de operações do programador

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

Para configurar esta infraestrutura, executa um script de configuração que inicia o processo de arranque e configura os componentes para o fluxo do GitOps.

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

  • Cria um repositório nos Cloud Source Repositories denominado copy-of-gcp-mig-simple e copia o código fonte do repositório de exemplo do GitHub para o repositório nos Cloud Source Repositories.
  • Cria dois acionadores do Cloud Build com os nomes apply e destroy.

O acionador apply está anexado a um ficheiro do Terraform denominado main.tfvars nos Cloud Source Repositories. Este ficheiro contém as variáveis do Terraform que representam os balanceadores de carga azuis e verdes.

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

  • Cria dois GIGs do Compute Engine (um para o verde e outro para o azul), quatro instâncias de VM do Compute Engine (duas para o GIG verde e duas para o GIG azul), os três balanceadores de carga (azul, verde e o divisor) e três endereços IP públicos.
  • Imprime os endereços IP que pode usar para ver as aplicações implementadas nas instâncias azuis e verdes.

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

Objetivos

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

  • Fazer implementações azul/verde nas instâncias de VM.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

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. Se estiver a usar um fornecedor de identidade (IdP) externo, primeiro, tem de iniciar sessão na CLI gcloud com a sua identidade federada.

  4. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  5. 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.

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

  7. Install the Google Cloud CLI.

  8. Se estiver a usar um fornecedor de identidade (IdP) externo, primeiro, tem de iniciar sessão na CLI gcloud com a sua identidade federada.

  9. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  10. 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.

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

  12. Experimentar

    1. Execute o script de configuração a partir do repositório de exemplos de código da 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 utilizador, introduza yes.

      O script termina a execução em alguns segundos.

    3. Na Google Cloud consola, abra a página Histórico de compilações do Cloud Build:

      Abra a página Criar histórico

    4. Clique na compilação mais recente.

      É apresentada a página Detalhes da compilação, que mostra um pipeline do Cloud Build com três passos de compilação: o primeiro passo de compilação cria um repositório nos Cloud Source Repositories, o segundo passo clona o conteúdo do repositório de exemplo no GitHub para os Cloud Source Repositories e o terceiro passo adiciona dois acionadores de compilação.

    5. Abra os Cloud Source Repositories:

      Abrir Cloud Source Repositories

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

      No separador Histórico na parte inferior da página, é apresentado um commit com a descrição A copy of https://github.com/GoogleCloudPlatform/cloud-build-samples.git criado pelo Cloud Build para criar um repositório com o nome copy-of-gcp-mig-simple.

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

      Abra a página Acionadores

    8. São apresentados dois acionadores de compilação com os nomes apply e destroy. O acionador apply está anexado ao ficheiro infra/main.tfvars no ramo main. Este acionador é executado sempre que o ficheiro é atualizado. O acionador destroy é um acionador manual.

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

      1. Na janela do terminal, crie e navegue para uma pasta com o nome 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 para 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 ficheiro atualizado:

        git add .
        
      6. Consolide o ficheiro:

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

        git push
        

        Fazer alterações a infra/main.tfvars aciona a execução do apply acionador, que inicia a implementação.

    10. Abra os Cloud Source Repositories:

      Abrir Cloud Source Repositories

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

      Verá a confirmação com a descrição Promote green no separador Histórico na parte inferior da página.

    12. Para ver a execução do acionador apply, abra a página Histórico de compilação na consola Google Cloud :

      Abra a página Criar histórico

    13. Abra a página Detalhes da compilação clicando na primeira compilação.

      É apresentada a pipeline de acionadores apply com dois passos de compilação. O primeiro passo de compilação executa o comando Terraform apply para criar os recursos do Compute Engine e de balanceamento de carga para a implementação. O segundo passo de compilação imprime o endereço IP onde pode ver a aplicação em execução.

    14. Abra o endereço IP correspondente ao MIG verde num navegador. É apresentada uma captura de ecrã semelhante à seguinte que mostra a implementação:

      Implementação

    15. Aceda à página Grupo de instâncias do Compute Engine para ver os grupos de instâncias azul e verde:

      Abra a página Grupo de instâncias

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

      Abra a página da instância de VM

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

      Abra a página Endereços IP externos

    Compreender o código

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

    • Código fonte relacionado com o script de configuração.
    • Código fonte relacionado com os pipelines do Cloud Build.
    • Código fonte relacionado com os modelos do Terraform.

    Script de configuração

    setup.sh é o script de configuração que executa o processo de arranque e cria os componentes para a implementação azul/verde. O script realiza as seguintes operações:

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

      • Cria um novo repositório nos Cloud Source Repositories.
      • Copia o código fonte do repositório GitHub de exemplo para o novo repositório nos Cloud Source Repositories.
      • Cria os acionadores de compilação de aplicação e destruição.
    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 ficheiros de configuração do Cloud Build que o script de configuração usa para configurar os recursos para o fluxo GitOps. apply.cloudbuild.yaml contém dois passos de compilação:

    • tf_apply build passo de criação que chama a função tf_install_in_cloud_build_step, que instala o Terraform. tf_apply que cria os recursos usados no fluxo GitOps. As funções tf_install_in_cloud_build_step e tf_apply são definidas em bash_utils.sh, e a etapa de compilação usa o comando source para as chamar.
    • describe_deployment passo de compilação que chama a função describe_deployment que imprime os endereços IP dos balanceadores de carga.

    destroy.cloudbuild.yaml chama tf_destroy que elimina todos os recursos criados por tf_apply.

    As funções tf_install_in_cloud_build_step, tf_apply, describe_deployment e tf_destroy estão definidas no ficheiro bash_utils.sh. Os ficheiros de configuração de compilação 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 seguinte mostra a função tf_install_in_cloud_build_step definida em bash_utils.sh. Os ficheiros de configuração da compilação chamam esta função para instalar o Terraform rapidamente. Cria um contentor do Cloud Storage para registar o estado 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 seguinte fragmento do código mostra a função tf_apply definida em bash_utils.sh. Primeiro, chama terraform init que carrega todos os módulos e bibliotecas personalizadas e, em seguida, executa terraform apply para carregar as variáveis do ficheiro 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 seguinte fragmento do código mostra a função describe_deployment definida em bash_utils.sh. Usa o gcloud compute addresses describe para obter os endereços IP dos balanceadores de carga através do nome e imprimi-los.

    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 seguinte fragmento do código mostra a função tf_destroy definida em bash_utils.sh. 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

    Vai encontrar todos os ficheiros de configuração e variáveis do Terraform na pasta copy-of-gcp-mig-simple/infra/.

    • main.tf: este é o ficheiro de configuração do Terraform
    • main.tfvars: este ficheiro define as variáveis do Terraform.
    • mig/ e splitter/: estas pastas contêm os módulos que definem os balanceadores de carga. A pasta mig/ contém o ficheiro de configuração do Terraform que define o MIG para os equilibradores de carga azul e verde. Os MIGs azuis e verdes são idênticos, pelo que são definidos uma vez e instanciados para os objetos azuis e verdes. O ficheiro de configuração do Terraform para o equilibrador de carga do divisor encontra-se na pasta splitter/ .

    O seguinte fragmento do código mostra o conteúdo de infra/main.tfvars. Contém três variáveis: duas que determinam que versão da aplicação implementar nos conjuntos azul e verde, e uma variável para a cor ativa: azul ou verde. As alterações a este ficheiro acionam a implementação.

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

    Segue-se um fragmento de código de infra/main.tf. Neste fragmento:

    • Uma variável está definida para o projeto Google Cloud .
    • A Google está definida como fornecedor do Terraform.
    • Uma variável é definida para o espaço de nomes. Todos os objetos criados pelo Terraform têm o prefixo desta variável para que seja possível implementar várias versões da aplicação no mesmo projeto e os nomes dos objetos não entrem em conflito entre si.
    • As variáveis MIG_VER_BLUE, MIG_VER_BLUE e MIG_ACTIVE_COLOR são as associações para as variáveis no ficheiro 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 seguinte fragmento do código de infra/main.tf mostra a instanciação do módulo de divisão. Este módulo recebe a cor ativa para que o balanceador de carga do divisor saiba em que MIG implementar a aplicação.

    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 seguinte fragmento do código de infra/main.tf define dois módulos idênticos para os MIGs azuis e verdes. Recebe a cor, a rede e a sub-rede, que são definidas no módulo 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 ficheiro splitter/main.tf define os objetos criados para o MIG do separador. Segue-se um fragmento de código de splitter/main.tf que contém a lógica para alternar entre o MIG verde e o azul. É suportado pelo serviço google_compute_region_backend_service, que pode encaminhar o tráfego para duas regiões de back-end: var.instance_group_blue ou var.instance_group_green. capacity_scaler define a quantidade de tráfego a encaminhar.

    O código seguinte encaminha 100% do tráfego para a cor especificada, mas pode atualizar este código para a implementação canary de modo a encaminhar o tráfego para um subconjunto dos utilizadores.

    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 ficheiro mig/main.tf define os objetos relativos aos MIGs azuis e verdes. O seguinte fragmento do código deste ficheiro define o modelo de instância do Compute Engine que é usado para criar os conjuntos de VMs. Tenha em atenção que este modelo de instância tem a propriedade do ciclo de vida do Terraform definida como create_before_destroy. Isto acontece porque, quando atualiza a versão do conjunto, não pode usar o modelo para criar a nova versão dos conjuntos quando ainda está a ser usado pela versão anterior do conjunto. No entanto, se a versão mais antiga do conjunto for destruída antes de criar o novo modelo, haverá um período em que os conjuntos estão inativos. Para evitar este cenário, definimos o ciclo de vida do Terraform como create_before_destroy para que a versão mais recente de um conjunto de VMs seja criada primeiro antes de a versão mais antiga ser 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 incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

    Elimine recursos individuais

    1. Elimine os recursos do Compute Engine criados pelo acionador de aplicação:

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

        Abra a página Acionadores

      2. Na tabela Acionadores, localize a linha correspondente ao acionador destroy e clique em Executar. Quando o acionador conclui a execução, os recursos criados pelo acionador apply são eliminados.

    2. Elimine os recursos criados durante o arranque executando o seguinte comando na janela do terminal:

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

    Elimine o projeto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    O que se segue?