Implementar en Compute Engine


En esta guía se explica cómo realizar implementaciones azul/verde sin tiempo de inactividad en grupos de instancias gestionados (MIGs) de Compute Engine mediante Cloud Build y Terraform.

Cloud Build te permite automatizar varios procesos de desarrollo, como compilar y desplegar aplicaciones en diferentes Google Cloud runtimes Google Cloud , como Compute Engine, Google Kubernetes Engine, GKE Enterprise y funciones de Cloud Run.

Los MIGs de Compute Engine te permiten operar aplicaciones en varias máquinas virtuales idénticas. Puedes hacer que tus cargas de trabajo sean escalables y tengan una alta disponibilidad aprovechando los servicios de MIG automatizados, como el autoescalado, la reparación automática, el despliegue regional (en varias zonas) y la actualización automática. Con el modelo de despliegue continuo azul/verde, aprenderás a transferir gradualmente el tráfico de usuarios de un MIG (azul) a otro (verde), ambos en producción.

Descripción general del diseño

En el siguiente diagrama se muestra el modelo de implementación azul/verde que utiliza el código de ejemplo descrito en este documento:

Modelo azul-verde

A grandes rasgos, este modelo incluye los siguientes componentes:

  • Dos grupos de máquinas virtuales de Compute Engine: azul y verde.
  • Tres balanceadores de carga HTTP(S) externos:
    • Un balanceador de carga azul/verde que dirige el tráfico de los usuarios finales al grupo azul o al verde de instancias de VM.
    • Un balanceador de carga azul que dirige el tráfico de los ingenieros de control de calidad y los desarrolladores al pool de instancias de VM azul.
    • Un balanceador de carga verde que dirige el tráfico de los ingenieros de control de calidad y los desarrolladores al grupo de instancias verde.
  • Dos conjuntos de usuarios:
    • Usuarios finales que tienen acceso al balanceador de carga azul/verde, que los dirige al grupo de instancias azul o al verde.
    • Ingenieros de control de calidad y desarrolladores que necesiten acceder a ambos conjuntos de grupos para desarrollar y probar. Pueden acceder tanto al balanceador de carga azul como al verde, que los dirige al grupo de instancias azul y al grupo de instancias verde, respectivamente.

Los grupos de máquinas virtuales azules y verdes se implementan como MIGs de Compute Engine, y las direcciones IP externas se enrutan a las máquinas virtuales del MIG mediante balanceadores de carga HTTP(S) externos. En el ejemplo de código que se describe en este documento se usa Terraform para configurar esta infraestructura.

En el siguiente diagrama se muestran las operaciones de desarrollador que se realizan en la implementación:

Flujo de operaciones de desarrolladores

En el diagrama anterior, las flechas rojas representan el flujo de bootstrapping que se produce cuando configuras la infraestructura de implementación por primera vez, y las flechas azules representan el flujo de GitOps que se produce durante cada implementación.

Para configurar esta infraestructura, ejecuta una secuencia de comandos de configuración que inicia el proceso de arranque y configura los componentes del flujo de GitOps.

La secuencia de comandos de configuración ejecuta una canalización de Cloud Build que realiza las siguientes operaciones:

El activador apply está asociado a un archivo de Terraform llamado main.tfvars en Cloud Source Repositories. Este archivo contiene las variables de Terraform que representan los balanceadores de carga azul y verde.

Para configurar la implementación, actualiza las variables del archivo main.tfvars. El activador apply ejecuta un flujo de procesamiento de Cloud Build que ejecuta tf_apply y realiza las siguientes operaciones:

  • Crea dos MIGs de Compute Engine (uno para la versión verde y otro para la azul), cuatro instancias de VM de Compute Engine (dos para el MIG verde y dos para el MIG azul), los tres balanceadores de carga (azul, verde y el divisor) y tres direcciones IP públicas.
  • Imprime las direcciones IP que puedes usar para ver las aplicaciones implementadas en las instancias azul y verde.

El activador de destrucción se activa manualmente para eliminar todos los recursos creados por el activador de aplicación.

Objetivos

  • Usa Cloud Build y Terraform para configurar balanceadores de carga HTTP(S) externos con backends de grupos de instancias de VM de Compute Engine.

  • Realiza despliegues azul-verde en las instancias de VM.

Costes

En este documento, se utilizan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costes basada en el uso previsto, utiliza la calculadora de precios.

Los usuarios nuevos Google Cloud pueden disfrutar de una prueba gratuita.

Cuando termines las tareas que se describen en este documento, puedes evitar que se te siga facturando eliminando los recursos que has creado. Para obtener más información, consulta la sección Limpiar.

Antes de empezar

  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. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  4. Para inicializar gcloud CLI, ejecuta el siguiente 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. Si utilizas un proveedor de identidades (IdP) externo, primero debes iniciar sesión en la CLI de gcloud con tu identidad federada.

  9. Para inicializar gcloud CLI, ejecuta el siguiente 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. Probar

    1. Ejecuta la secuencia de comandos de configuración desde el repositorio de códigos de ejemplo de Google:

      bash <(curl https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-build-samples/main/mig-blue-green/setup.sh)
      
    2. Cuando la secuencia de comandos de configuración te pida el consentimiento del usuario, introduce yes.

      La secuencia de comandos termina de ejecutarse en unos segundos.

    3. En la Google Cloud consola, abre la página Historial de compilaciones de Cloud Build:

      Abrir la página Historial de compilaciones

    4. Haz clic en la compilación más reciente.

      Verás la página Detalles de la compilación, que muestra una canalización de Cloud Build con tres pasos: el primero crea un repositorio en Cloud Source Repositories, el segundo clona el contenido del repositorio de ejemplo de GitHub en Cloud Source Repositories y el tercero añade dos activadores de compilación.

    5. Abre Cloud Source Repositories:

      Abrir Cloud Source Repositories

    6. En la lista de repositorios, haga clic en copy-of-gcp-mig-simple.

      En la pestaña Historial, situada en la parte inferior de la página, verás una confirmación con la descripción A copy of https://github.com/GoogleCloudPlatform/cloud-build-samples.git que ha creado Cloud Build para crear un repositorio llamado copy-of-gcp-mig-simple.

    7. Abre la página Activadores de Cloud Build:

      Abrir la página Activadores

    8. Verás dos activadores de compilación llamados apply y destroy. El activador apply está asociado al archivo infra/main.tfvars de la rama main. Este activador se ejecuta cada vez que se actualiza el archivo. El activador destroy es un activador manual.

    9. Para iniciar el proceso de implementación, actualice el archivo infra/main.tfvars:

      1. En la ventana de terminal, crea una carpeta llamada deploy-compute-engine y accede a ella:

        mkdir ~/deploy-compute-engine
        cd ~/deploy-compute-engine
        
      2. Clona el repositorio copy-of-gcp-mig-simple:

        gcloud source repos clone copy-of-mig-blue-green
        
      3. Ve al directorio clonado:

        cd ./copy-of-mig-blue-green
        
      4. Actualiza infra/main.tfvars para sustituir el azul por el verde:

        sed -i'' -e 's/blue/green/g' infra/main.tfvars
        
      5. Añade el archivo actualizado:

        git add .
        
      6. Confirma el archivo:

        git commit -m "Promote green"
        
      7. Envía el archivo:

        git push
        

        Si se hacen cambios en infra/main.tfvars, se activa el apply trigger, que inicia la implementación.

    10. Abre Cloud Source Repositories:

      Abrir Cloud Source Repositories

    11. En la lista de repositorios, haga clic en copy-of-gcp-mig-simple.

      Verás la confirmación con la descripción Promote green en la pestaña Historial, en la parte inferior de la página.

    12. Para ver la ejecución del activador apply, abra la página Historial de compilación en la consola Google Cloud :

      Abrir la página Historial de compilaciones

    13. Abre la página Detalles de la compilación haciendo clic en la primera compilación.

      Verás la canalización de activación apply con dos pasos de compilación. El primer paso de compilación ejecuta Terraform apply para crear los recursos de Compute Engine y de balanceo de carga de la implementación. En el segundo paso de compilación se muestra la dirección IP en la que puedes ver la aplicación en ejecución.

    14. Abre la dirección IP correspondiente al MIG verde en un navegador. Verá una captura de pantalla similar a la siguiente, que muestra la implementación:

      Implementación

    15. Ve a la página Grupo de instancias de Compute Engine para ver los grupos de instancias azul y verde:

      Abre la página Grupo de instancias.

    16. Abre la página Instancias de VM para ver las cuatro instancias de VM:

      Abre la página Instancia de VM.

    17. Abre la página Direcciones IP externas para ver los tres balanceadores de carga:

      Abre la página Direcciones IP externas

    Información sobre el código

    El código fuente de este ejemplo de código incluye lo siguiente:

    • Código fuente relacionado con la secuencia de comandos de configuración.
    • Código fuente relacionado con las canalizaciones de Cloud Build.
    • Código fuente relacionado con las plantillas de Terraform.

    Secuencia de comandos de configuración

    setup.sh es la secuencia de comandos de configuración que ejecuta el proceso de arranque y crea los componentes del despliegue azul-verde. La secuencia de comandos realiza las siguientes operaciones:

    • Habilita las APIs Cloud Build, Resource Manager, Compute Engine y Cloud Source Repositories.
    • Concede el rol de IAM roles/editor a la cuenta de servicio de Cloud Build de tu proyecto. Este rol es necesario para que Cloud Build cree y configure los componentes de GitOps necesarios para la implementación.
    • Concede el rol de IAM roles/source.admin a la cuenta de servicio de Cloud Build de tu proyecto. Este rol es necesario para que la cuenta de servicio de Cloud Build cree los repositorios de Cloud Source en tu proyecto y clone el contenido del repositorio de GitHub de ejemplo en tus repositorios de Cloud Source.
    • Genera un flujo de procesamiento de Cloud Build llamado bootstrap.cloudbuild.yaml en línea que hace lo siguiente:

      • Crea un repositorio en Cloud Source Repositories.
      • Copia el código fuente del repositorio de ejemplo de GitHub en el nuevo repositorio de Cloud Source Repositories.
      • Crea los activadores de compilación de aplicación y destrucción.
    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 de Cloud Build

    apply.cloudbuild.yaml y destroy.cloudbuild.yaml son los archivos de configuración de Cloud Build que usa la secuencia de comandos de configuración para configurar los recursos del flujo de GitOps. apply.cloudbuild.yaml contiene dos pasos de compilación:

    • tf_apply build paso de compilación que llama a la función tf_install_in_cloud_build_step, que instala Terraform. tf_apply que crea los recursos que se usan en el flujo de GitOps. Las funciones tf_install_in_cloud_build_step y tf_apply se definen en bash_utils.sh y el paso de compilación usa el comando source para llamarlas.
    • describe_deployment paso de compilación que llama a la función describe_deployment que imprime las direcciones IP de los balanceadores de carga.

    destroy.cloudbuild.yaml llama a tf_destroy, que elimina todos los recursos creados por tf_apply.

    Las funciones tf_install_in_cloud_build_step, tf_apply, describe_deployment y tf_destroy se definen en el archivo bash_utils.sh. Los archivos de configuración de compilación usan el comando source para llamar a las funciones.

    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"

    En el siguiente código se muestra la función tf_install_in_cloud_build_step definida en bash_utils.sh. Los archivos de configuración de compilación llaman a esta función para instalar Terraform sobre la marcha. Crea un segmento de Cloud Storage para registrar el estado de 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)"
    }

    El siguiente fragmento de código muestra la función tf_apply definida en bash_utils.sh. Primero, llama a terraform init, que carga todos los módulos y las bibliotecas personalizadas, y, a continuación, ejecuta terraform apply para cargar las variables del archivo 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"
    }

    El siguiente fragmento de código muestra la función describe_deployment definida en bash_utils.sh. Usa gcloud compute addresses describe para obtener las direcciones IP de los balanceadores de carga mediante el nombre y las 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!"
    }

    El siguiente fragmento de código muestra la función tf_destroy definida en bash_utils.sh. Llama a terraform init, que carga todos los módulos y las bibliotecas personalizadas, y, a continuación, ejecuta terraform destroy, que descarga las variables de 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"
    }

    Plantillas de Terraform

    En la carpeta copy-of-gcp-mig-simple/infra/ encontrarás todos los archivos de configuración y las variables de Terraform.

    • main.tf: es el archivo de configuración de Terraform.
    • main.tfvars: este archivo define las variables de Terraform.
    • mig/ y splitter/: estas carpetas contienen los módulos que definen los balanceadores de carga. La carpeta mig/ contiene el archivo de configuración de Terraform que define el MIG de los balanceadores de carga azul y verde. Los MIGs azul y verde son idénticos, por lo que se definen una vez y se instancian para los objetos azul y verde. El archivo de configuración de Terraform del balanceador de carga de división se encuentra en la carpeta splitter/ .

    El siguiente fragmento de código muestra el contenido de infra/main.tfvars. Contiene tres variables: dos que determinan qué versión de la aplicación se va a implementar en los grupos Azul y Verde, y una variable para el color activo: Azul o Verde. Los cambios en este archivo activan el despliegue.

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

    A continuación, se muestra un fragmento de código de infra/main.tf. En este fragmento:

    • Se ha definido una variable para el proyecto Google Cloud .
    • Google se ha definido como proveedor de Terraform.
    • Se define una variable para el espacio de nombres. Todos los objetos creados por Terraform tienen como prefijo esta variable, de modo que se puedan desplegar varias versiones de la aplicación en el mismo proyecto y los nombres de los objetos no entren en conflicto entre sí.
    • Las variables MIG_VER_BLUE, MIG_VER_BLUE y MIG_ACTIVE_COLOR son las enlaces de las variables del archivo 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)."
    }

    En el siguiente fragmento de código de infra/main.tf se muestra la instanciación del módulo de divisor. Este módulo recibe el color activo para que el balanceador de carga del divisor sepa en qué MIG debe implementar la aplicación.

    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
    }

    El siguiente fragmento de código de infra/main.tf define dos módulos idénticos para MIGs azules y verdes. Recibe el color, la red y la subred que se definen en el módulo de división.

    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
    }

    El archivo splitter/main.tf define los objetos que se crean para el MIG de divisor. A continuación, se muestra un fragmento de código de splitter/main.tf que contiene la lógica para cambiar entre el MIG verde y el azul. Se basa en el servicio google_compute_region_backend_service, que puede enrutar el tráfico a dos regiones de backend: var.instance_group_blue o var.instance_group_green. capacity_scaler define la cantidad de tráfico que se va a enrutar.

    El siguiente código dirige el 100% del tráfico al color especificado, pero puedes actualizarlo para la implementación canary y dirigir el tráfico a un subconjunto de usuarios.

    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
      }
    }

    El archivo mig/main.tf define los objetos correspondientes a los MIGs azul y verde. El siguiente fragmento de código de este archivo define la plantilla de instancia de Compute Engine que se usa para crear los grupos de máquinas virtuales. Ten en cuenta que esta plantilla de instancia tiene la propiedad de ciclo de vida de Terraform definida como create_before_destroy. Esto se debe a que, al actualizar la versión del grupo, no puede usar la plantilla para crear la nueva versión de los grupos cuando la versión anterior del grupo aún la esté usando. Sin embargo, si la versión anterior del grupo se destruye antes de crear la nueva plantilla, habrá un periodo en el que los grupos no funcionarán. Para evitar esta situación, hemos definido el ciclo de vida de Terraform como create_before_destroy para que se cree primero la versión más reciente de un pool de VMs antes de que se destruya la versión anterior.

    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
      }
    }

    Limpieza

    Para evitar que los recursos utilizados en este tutorial se cobren en tu cuenta de Google Cloud, elimina el proyecto que contiene los recursos o conserva el proyecto y elimina los recursos.

    Eliminar recursos concretos

    1. Elimina los recursos de Compute Engine creados por el activador de aplicación:

      1. Abre la página Activadores de Cloud Build:

        Abrir la página Activadores

      2. En la tabla Activadores, busque la fila correspondiente al activador destroy y haga clic en Ejecutar. Cuando el activador termina de ejecutarse, se eliminan los recursos creados por el activador apply.

    2. Elimina los recursos creados durante el bootstrapping ejecutando el siguiente comando en la ventana de terminal:

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

    Eliminar el proyecto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Siguientes pasos