Implementa en Compute Engine


En esta guía, se explica cómo realizar implementaciones azul-verde sin tiempo de inactividad en los grupos de instancias administrados de Compute Engine (MIG) mediante Cloud Build y Terraform.

Cloud Build te permite automatizar una variedad de procesos de desarrollador, incluida la compilación y la implementación de aplicaciones en varios entornos de ejecución de Google Cloud, como Compute Engine, Google Kubernetes Engine, GKE Enterprise y Cloud Functions.

Los MIG de Compute Engine te permiten operar aplicaciones en varias máquinas virtuales (VMs) idénticas. Puedes hacer que tus cargas de trabajo sean escalables y con alta disponibilidad mediante los servicios de MIG automatizados, incluidos el ajuste de escala automático, la reparación automática, la implementación regional (en varias zonas) y la actualización automática. Con el modelo de implementación continua azul-verde, aprenderás a transferir de forma gradual el tráfico de usuarios de un MIG (azul) a otro MIG (verde), que se ejecutan en producción.

Descripción general del diseño

En el siguiente diagrama, se muestra el modelo de implementación azul-verde que usa la muestra de código descrita en este documento:

Modelo azul-verde

En un nivel alto, este modelo incluye los siguientes componentes:

  • Dos grupos de VMs de Compute Engine: azul y verde.
  • Tres balanceadores de cargas de HTTP(S) externos:
    • Un balanceador de cargas azul-verde, que enruta el tráfico de los usuarios finales al grupo azul o verde de las instancias de VM
    • Un balanceador de cargas azul que enruta el tráfico de los ingenieros y desarrolladores de QA al grupo de instancias de VM azul
    • Un balanceador de cargas verde que enruta el tráfico de los ingenieros y desarrolladores de QA al grupo de instancias de Green
  • Dos conjuntos de usuarios:
    • Usuarios finales que tienen acceso al balanceador de cargas Azul-verde, que los dirige al grupo de instancias Azul o Verde.
    • Ingenieros y desarrolladores de QA que requieren acceso a ambos conjuntos de grupos con fines de desarrollo y prueba Puede acceder a los balanceadores de cargas azul y verde, que los enruta al grupo de instancias azul y al grupo de instancias verde, respectivamente.

Los grupos de VMs Azul y Verde se implementan como MIG de Compute Engine, y las direcciones IP externas se enrutan a las VMs en el MIG mediante balanceadores de cargas de HTTP(s) externos. En la muestra de código que se describe en este documento, se usa Terraform para configurar esta infraestructura.

En el siguiente diagrama, se ilustran las operaciones del desarrollador que se llevan a cabo en la implementación:

Flujo de operaciones del desarrollador

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

Para configurar esta infraestructura, ejecuta una secuencia de comandos de configuración que inicie el proceso de arranque y configure 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 se conecta a un archivo de Terraform llamado main.tfvars en Cloud Source Repositories. Este archivo contiene las variables de Terraform que representan los balanceadores de cargas azul y verde.

Para configurar la implementación, actualiza las variables en el archivo main.tfvars. El activador apply ejecuta una canalización de Cloud Build que ejecuta tf_apply y realiza las siguientes operaciones:

  • Crea dos MIG de Compute Engine (uno para el verde y otro para el azul), cuatro instancias de VM de Compute Engine (dos para el MIG verde y dos para el MIG azul), los tres balanceadores de cargas (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 de forma manual para borrar todos los recursos que creó el activador de aplicación.

Objetivos

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

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

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud califiquen para obtener una prueba gratuita.

Cuando finalices las tareas que se describen en este documento, puedes borrar los recursos que creaste para evitar que continúe la facturación. Para obtener más información, consulta Cómo realizar una limpieza.

Antes de comenzar

  1. Accede a tu cuenta de Google Cloud. Si eres nuevo en Google Cloud, crea una cuenta para evaluar el rendimiento de nuestros productos en situaciones reales. Los clientes nuevos también obtienen $300 en créditos gratuitos para ejecutar, probar y, además, implementar cargas de trabajo.
  2. Instala Google Cloud CLI.
  3. Para inicializar la CLI de gcloud, ejecuta el siguiente comando:

    gcloud init
  4. Crea o selecciona un proyecto de Google Cloud.

    • Crea un proyecto de Google Cloud:

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto de Google Cloud que estás creando.

    • Selecciona el proyecto de Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre del proyecto de Google Cloud.

  5. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  6. Instala Google Cloud CLI.
  7. Para inicializar la CLI de gcloud, ejecuta el siguiente comando:

    gcloud init
  8. Crea o selecciona un proyecto de Google Cloud.

    • Crea un proyecto de Google Cloud:

      gcloud projects create PROJECT_ID

      Reemplaza PROJECT_ID por un nombre para el proyecto de Google Cloud que estás creando.

    • Selecciona el proyecto de Google Cloud que creaste:

      gcloud config set project PROJECT_ID

      Reemplaza PROJECT_ID por el nombre del proyecto de Google Cloud.

  9. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

Prueba

  1. Ejecuta la secuencia de comandos de configuración desde el repositorio de muestra de código 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 solicite el consentimiento del usuario, ingresa yes.

    La secuencia de comandos termina de ejecutarse en unos segundos.

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

    Abrir la página Historial de compilación

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

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

  5. Abre Cloud Source Repositories:

    Abrir Cloud Source Repositories

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

    En la pestaña Historial, 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 realizó 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 se adjunta al archivo infra/main.tfvars en la rama main. Este activador se ejecuta cada vez que se actualiza el archivo. El activador destroy es manual.

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

    1. En la ventana de tu terminal, crea una carpeta llamada deploy-compute-engine y navega hacia 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. Navega al directorio clonado:

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

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

      git add .
      
    6. Confirma el archivo:

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

      git push
      

      Realizar cambios en infra/main.tfvars activa la ejecución del activador apply, que inicia la implementación.

  10. Abre Cloud Source Repositories:

    Abrir Cloud Source Repositories

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

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

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

    Abrir la página Historial de compilación

  13. Haz clic en la primera compilación para abrir la página Build details.

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

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

    Deployment

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

    Abrir la página Grupo de instancias

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

    Abrir la página Instancia de VM

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

    Abrir la página Direcciones IP externas

Comprende el código

El código fuente de esta muestra 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 para la implementación azul-verde. La secuencia de comandos realiza las siguientes operaciones:

  • Habilita las APIs de Cloud Build, Resource Manager, Compute Engine y Cloud Source Repositories.
  • Otorga el rol de IAM roles/editor a la cuenta de servicio de Cloud Build en tu proyecto. Esta función es obligatoria para que Cloud Build cree y configure los componentes de GitOps necesarios para la implementación.
  • Otorga el rol de IAM roles/source.admin a la cuenta de servicio de Cloud Build en tu proyecto. Esta función es necesaria para que la cuenta de servicio de Cloud Build cree los Cloud Source Repositories en tu proyecto y clone el contenido del repositorio de GitHub de muestra en tus Cloud Source Repositories.
  • Genera una canalización de Cloud Build llamada bootstrap.cloudbuild.yaml intercalada que:

    • Crea un repositorio nuevo en Cloud Source Repositories.
    • Copia el código fuente del repositorio de GitHub de muestra al repositorio nuevo en Cloud Source Repositories.
    • Crea los activadores de compilación para aplicar y destruir.
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}"

Canalizaciones de Cloud Build

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

  • tf_apply build 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 que llama a la función describe_deployment que imprime las direcciones IP de los balanceadores de cargas.

destroy.cloudbuild.yaml llama a tf_destroy, que borra todos los recursos que creó 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 que se define 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 bucket 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)"
}

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

En el siguiente fragmento de código, se muestra la función describe_deployment definida en bash_utils.sh. Usa gcloud compute addresses describe para recuperar las direcciones IP de los balanceadores de cargas que usan el nombre y, luego, 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!"
}

En el siguiente fragmento de código, se muestra la función tf_destroy que se define en bash_utils.sh. Llama a terraform init, que carga todos los módulos y bibliotecas personalizadas, y, luego, 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

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

  • main.tf: Este 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 cargas. La carpeta mig/ contiene el archivo de configuración de Terraform que define el MIG para los balanceadores de cargas azul y verde. Los MIG azul y el verde son idénticos, por lo que se definen una vez y se crean instancias de los objetos azules y verdes. El archivo de configuración de Terraform para el balanceador de cargas del divisor se encuentra en la carpeta splitter/ .

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

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

El siguiente es un fragmento de código de infra/main.tf. En este fragmento, se incluye lo siguiente:

  • Se define una variable para el proyecto de Google Cloud.
  • Se establece Google como el proveedor de Terraform.
  • Se define una variable para el espacio de nombres. Todos los objetos creados por Terraform tienen el prefijo de esta variable para que se puedan implementar varias versiones de la aplicación en el mismo proyecto y los nombres de los objetos no entren en conflicto.
  • Las variables MIG_VER_BLUE, MIG_VER_BLUE y MIG_ACTIVE_COLOR son las vinculaciones 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 creación de instancias del módulo divisor. Este módulo toma el color activo para que el balanceador de cargas del divisor sepa 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
}

En el siguiente fragmento de código de infra/main.tf, se definen dos módulos idénticos para los MIG azules y verdes. Toma el color, la red y la subred, que se definen en el 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
}

El archivo splitter/main.tf define los objetos que se crean para el MIG divisor. El siguiente es un fragmento de código de splitter/main.tf que contiene la lógica para alternar entre el MIG verde y el azul. Cuenta con el respaldo del 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 cuánto tráfico se enrutará.

El siguiente código enruta el 100% del tráfico al color especificado, pero puedes actualizar este código para la implementación de versiones canary y, así, enrutar el tráfico a un subconjunto de los 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 MIG azules y verdes. En el siguiente fragmento de código de este archivo, se define la plantilla de instancias de Compute Engine que se usa para crear los grupos de VM. Ten en cuenta que esta plantilla de instancias tiene la propiedad del ciclo de vida de Terraform establecida en create_before_destroy. Esto se debe a que, cuando actualizas la versión del grupo, no puedes usar la plantilla para crear la versión nueva de los grupos cuando la versión anterior del grupo aún lo usa. Sin embargo, si se destruye la versión anterior del grupo antes de crear la plantilla nueva, habrá un período en el que los grupos dejarán de funcionar. Para evitar esta situación, configuramos el ciclo de vida de Terraform en create_before_destroy para que la versión más reciente de un grupo de VM se cree primero antes de que se destruya la 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
  }
}

Limpia

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Borra los recursos individuales

  1. Borra los recursos de Compute Engine que creó el activador de aplicación:

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

      Abrir la página Activadores

    2. En la tabla Activadores, ubica la fila correspondiente al activador destroy y haz clic en Ejecutar. Cuando el activador completa la ejecución, se borran los recursos creados por el activador apply.

  2. Borra los recursos creados durante el arranque mediante la ejecución del siguiente comando en la ventana de la terminal:

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

Borra el proyecto

    Borra un proyecto de Google Cloud:

    gcloud projects delete PROJECT_ID

¿Qué sigue?