Für Compute Engine bereitstellen


In dieser Anleitung wird erläutert, wie Sie mit Cloud Build und Terraform Blau/Grün-Bereitstellungen ohne Ausfallzeiten in verwalteten Compute Engine-Instanzgruppen (MIGs) ausführen.

Mit Cloud Build können Sie eine Vielzahl von Entwicklerprozessen automatisieren, darunter das Erstellen und Bereitstellen von Anwendungen in verschiedenen Google Cloud-Laufzeiten wie Compute Engine, Google Kubernetes Engine, GKE Enterprise und Cloud Functions.

Mit Compute Engine-MIGs können Sie Anwendungen auf mehreren identischen virtuellen Maschinen (VMs) ausführen. Sie können Ihre Arbeitslasten skalierbar und hochverfügbar machen, indem Sie automatisierte MIG-Dienste nutzen, darunter Autoscaling, automatische Reparatur, regionale Bereitstellung (in mehreren Zonen) und automatische Updates. Mit dem Blau/Grün-Modell für kontinuierliche Bereitstellung erfahren Sie, wie Sie Nutzertraffic schrittweise von einer verwalteten Instanzgruppe (blau) auf eine andere verwaltete Instanzgruppe (grün) übertragen, die beide in der Produktion ausgeführt werden.

Designübersicht

Das folgende Diagramm zeigt das Blau/Grün-Bereitstellungsmodell, das im Codebeispiel in diesem Dokument verwendet wird:

Blau/Grün-Modell

Grundsätzlich umfasst dieses Modell die folgenden Komponenten:

  • Zwei Compute Engine-VM-Pools: Blau und Grün.
  • Drei externe HTTP(S)-Load-Balancer:
    • Ein Blau/Grün-Load-Balancer, der den Traffic von Endnutzern entweder zum blauen oder zum grünen Pool von VM-Instanzen weiterleitet.
    • Ein blauer Load Balancer, der den Traffic von QA-Entwicklern und -Entwicklern an den blauen VM-Instanzpool weiterleitet
    • Ein grüner Load-Balancer, der den Traffic von QA-Entwicklern und -Entwicklern an den grünen Instanzpool weiterleitet.
  • Zwei Nutzergruppen:
    • Endnutzer, die Zugriff auf den Blau/Grün-Load-Balancer haben, der sie entweder auf den blauen oder den grünen Instanzpool verweist.
    • QA-Entwickler und -Entwickler, die für Entwicklungs- und Testzwecke Zugriff auf beide Gruppen von Pools benötigen. Sie können auf die blauen und den grünen Load-Balancer zugreifen, die sie jeweils an den blauen und den grünen Instanzpool weiterleiten.

Die blauen und grünen VM-Pools werden als Compute Engine-MIGs implementiert und externe IP-Adressen werden über externe HTTP(S)-Load-Balancer an die VMs in der verwalteten Instanzgruppe weitergeleitet. Im hier beschriebenen Codebeispiel wird Terraform verwendet, um diese Infrastruktur zu konfigurieren.

Das folgende Diagramm veranschaulicht die Entwicklervorgänge, die bei der Bereitstellung stattfinden:

Ablauf des Entwicklerbetriebs

Im obigen Diagramm stellen die roten Pfeile den Bootstrapping-Ablauf beim ersten Einrichten der Bereitstellungsinfrastruktur dar. Die blauen Pfeile stellen den GitOps-Ablauf während jeder Bereitstellung dar.

Zum Einrichten dieser Infrastruktur führen Sie ein Einrichtungsskript aus, das den Bootstrap-Prozess startet und die Komponenten für den GitOps-Ablauf einrichtet.

Das Einrichtungsskript führt eine Cloud Build-Pipeline aus, die die folgenden Vorgänge ausführt:

  • Ein Repository mit dem Namen copy-of-gcp-mig-simple in Cloud Source Repositories wird erstellt und der Quellcode aus dem GitHub-Beispiel-Repository wird in das Repository in Cloud Source Repositories kopiert.
  • Es werden zwei Cloud Build-Trigger mit den Namen apply und destroy erstellt.

Der apply-Trigger ist an eine Terraform-Datei mit dem Namen main.tfvars in Cloud Source Repositories angehängt. Diese Datei enthält die Terraform-Variablen, die die blauen und die grünen Load-Balancer darstellen.

Aktualisieren Sie die Variablen in der Datei main.tfvars, um die Bereitstellung einzurichten. Der apply-Trigger führt eine Cloud Build-Pipeline aus, die tf_apply und die folgenden Vorgänge ausführt:

  • Erstellt zwei Compute Engine-MIGs (eine für Grün und eine für Blau), vier Compute Engine-VM-Instanzen (zwei für die grüne MIG und zwei für die blaue MIG), die drei Load-Balancer (Blau, Grün und den Splitter) und drei öffentliche IP-Adressen.
  • Gibt die IP-Adressen aus, mit denen Sie die bereitgestellten Anwendungen in den blauen und den grünen Instanzen sehen können.

Der Löschtrigger wird manuell ausgelöst, um alle Ressourcen zu löschen, die vom Trigger zum Anwenden erstellt wurden.

Lernziele

  • Verwenden Sie Cloud Build und Terraform, um externe HTTP(S)-Load-Balancer mit Compute Engine-VM-Instanzgruppen-Back-Ends einzurichten.

  • Blau/Grün-Bereitstellungen auf den VM-Instanzen ausführen

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweise

  1. Melden Sie sich bei Ihrem Google Cloud-Konto an. Wenn Sie mit Google Cloud noch nicht vertraut sind, erstellen Sie ein Konto, um die Leistungsfähigkeit unserer Produkte in der Praxis sehen und bewerten zu können. Neukunden erhalten außerdem ein Guthaben von 300 $, um Arbeitslasten auszuführen, zu testen und bereitzustellen.
  2. Installieren Sie die Google Cloud CLI.
  3. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  4. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  5. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

  6. Installieren Sie die Google Cloud CLI.
  7. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    gcloud init
  8. Google Cloud-Projekt erstellen oder auswählen.

    • Erstellen Sie ein Google Cloud-Projekt:

      gcloud projects create PROJECT_ID

      Ersetzen Sie PROJECT_ID durch einen Namen für das Google Cloud-Projekt, das Sie erstellen.

    • Wählen Sie das von Ihnen erstellte Google Cloud-Projekt aus:

      gcloud config set project PROJECT_ID

      Ersetzen Sie PROJECT_ID durch den Namen Ihres Google Cloud-Projekts.

  9. Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.

Testen

  1. Führen Sie das Einrichtungsskript aus dem Codebeispiel-Repository von Google aus:

    bash <(curl https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-build-samples/main/mig-blue-green/setup.sh)
    
  2. Wenn das Einrichtungsskript die Nutzereinwilligung anfordert, geben Sie yes ein.

    Das Skript ist in einigen Sekunden fertig.

  3. Rufen Sie in der Google Cloud Console die Cloud Build-Seite Build-Verlauf auf:

    Zur Seite „Build-Verlauf“

  4. Klicken Sie auf den neuesten Build.

    Sie sehen die Seite Build-Details. Hier wird eine Cloud Build-Pipeline mit drei Build-Schritten angezeigt: Mit dem ersten Build-Schritt wird ein Repository in Cloud Source Repositories erstellt, mit dem zweiten Schritt wird der Inhalt des Beispiel-Repositorys in GitHub in Cloud Source Repositories geklont und im dritten Schritt werden zwei Build-Trigger hinzugefügt.

  5. Öffnen Sie Cloud Source Repositories:

    Cloud Source Repositories öffnen

  6. Klicken Sie in der Liste der Repositories auf copy-of-gcp-mig-simple.

    Auf dem Tab Verlauf unten auf der Seite wird ein Commit mit der Beschreibung A copy of https://github.com/GoogleCloudPlatform/cloud-build-samples.git angezeigt, der von Cloud Build zum Erstellen eines Repositorys mit dem Namen copy-of-gcp-mig-simple erstellt wurde.

  7. Öffnen Sie die Cloud Build-Seite Trigger:

    Zur Seite "Trigger"

  8. Sie sehen zwei Build-Trigger mit den Namen apply und destroy. Der Trigger apply ist an die Datei infra/main.tfvars im Zweig main angehängt. Dieser Trigger wird jedes Mal ausgeführt, wenn die Datei aktualisiert wird. Der destroy-Trigger ist ein manueller Trigger.

  9. Aktualisieren Sie die Datei infra/main.tfvars, um den Bereitstellungsprozess zu starten:

    1. Erstellen Sie in Ihrem Terminalfenster einen Ordner mit dem Namen deploy-compute-engine und rufen Sie ihn auf:

      mkdir ~/deploy-compute-engine
      cd ~/deploy-compute-engine
      
    2. Klonen Sie das copy-of-gcp-mig-simple-Repo:

      gcloud source repos clone copy-of-mig-blue-green
      
    3. Gehen Sie zum geklonten Verzeichnis:

      cd ./copy-of-mig-blue-green
      
    4. infra/main.tfvars aktualisieren, um Blau durch Grün zu ersetzen:

      sed -i'' -e 's/blue/green/g' infra/main.tfvars
      
    5. Fügen Sie die aktualisierte Datei hinzu:

      git add .
      
    6. Führen Sie mit der Datei ein Commit durch:

      git commit -m "Promote green"
      
    7. Übertragen Sie die Datei per Push:

      git push
      

      Wenn Sie Änderungen an infra/main.tfvars vornehmen, wird der apply-Trigger ausgeführt, der die Bereitstellung startet.

  10. Öffnen Sie Cloud Source Repositories:

    Cloud Source Repositories öffnen

  11. Klicken Sie in der Liste der Repositories auf copy-of-gcp-mig-simple.

    Sie sehen den Commit mit der Beschreibung Promote green auf dem Tab Verlauf unten auf der Seite.

  12. Wenn Sie die Ausführung des apply-Triggers ansehen möchten, öffnen Sie in der Google Cloud Console die Seite Build-Verlauf:

    Zur Seite „Build-Verlauf“

  13. Öffnen Sie die Seite Build-Details, indem Sie auf den ersten Build klicken.

    Sie sehen die Triggerpipeline apply mit zwei Build-Schritten. Der erste Build-Schritt führt Terraform apply aus, um die Compute Engine- und Load-Balancing-Ressourcen für die Bereitstellung zu erstellen. Im zweiten Build-Schritt wird die IP-Adresse ausgegeben, unter der Sie die ausgeführte Anwendung sehen können.

  14. Öffnen Sie die IP-Adresse der grünen MIG in einem Browser. Sie sehen einen Screenshot ähnlich dem folgenden, der die Bereitstellung zeigt:

    Bereitstellung

  15. Rufen Sie die Compute Engine-Seite Instanzgruppe auf, um die Instanzgruppen Blau und Grün zu sehen:

    Zur Seite „Instanzgruppen“

  16. Öffnen Sie die Seite VM-Instanzen, um die vier VM-Instanzen zu sehen:

    Zur Seite "VM-Instanzen"

  17. Öffnen Sie die Seite Externe IP-Adressen, um die drei Load-Balancer zu sehen:

    Zur Seite „Externe IP-Adressen“

Code verstehen

Der Quellcode für dieses Codebeispiel umfasst Folgendes:

  • Quellcode für das Einrichtungsskript.
  • Quellcode für die Cloud Build-Pipelines.
  • Quellcode für die Terraform-Vorlagen.

Setup script

setup.sh ist das Einrichtungsskript, das den Bootstrap-Prozess ausführt und die Komponenten für die Blau/Grün-Bereitstellung erstellt. Das Skript führt die folgenden Vorgänge aus:

  • Die APIs Cloud Build, Resource Manager, Compute Engine und Cloud Source Repositories werden aktiviert.
  • Gewährt dem Cloud Build-Dienstkonto in Ihrem Projekt die IAM-Rolle roles/editor. Diese Rolle ist erforderlich, damit Cloud Build die erforderlichen GitOps-Komponenten für die Bereitstellung erstellen und einrichten kann.
  • Gewährt dem Cloud Build-Dienstkonto in Ihrem Projekt die IAM-Rolle roles/source.admin. Diese Rolle ist für das Cloud Build-Dienstkonto erforderlich, um die Cloud Source Repositories in Ihrem Projekt zu erstellen und den Inhalt des GitHub-Beispiel-Repositorys in Ihre Cloud Source Repositories zu klonen.
  • Generiert eine Cloud Build-Pipeline namens bootstrap.cloudbuild.yaml inline, die:

    • Erstellt ein neues Repository in Cloud Source Repositories.
    • Kopiert den Quellcode aus dem Beispiel-GitHub-Repository in das neue Repository in Cloud Source Repositories.
    • Erstellt die Build-Trigger für das Anwenden und Löschen.
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}"

Cloud Build-Pipelines

apply.cloudbuild.yaml und destroy.cloudbuild.yaml sind die Cloud Build-Konfigurationsdateien, mit denen das Einrichtungsskript die Ressourcen für den GitOps-Ablauf einrichtet. apply.cloudbuild.yaml enthält zwei Build-Schritte:

  • Build-Schritt tf_apply build, mit dem die Funktion tf_install_in_cloud_build_step aufgerufen wird, mit der Terraform installiert wird. tf_apply, der die im GitOps-Ablauf verwendeten Ressourcen erstellt. Die Funktionen tf_install_in_cloud_build_step und tf_apply sind in bash_utils.sh definiert und im Build-Schritt werden sie mit dem Befehl source aufgerufen.
  • Build-Schritt describe_deployment, der die Funktion describe_deployment aufruft, die die IP-Adressen der Load-Balancer ausgibt.

destroy.cloudbuild.yaml ruft tf_destroy auf, um alle von tf_apply erstellten Ressourcen zu löschen.

Die Funktionen tf_install_in_cloud_build_step, tf_apply, describe_deployment und tf_destroy sind in der Datei bash_utils.sh definiert. Die Build-Konfigurationsdateien verwenden den Befehl source, um die Funktionen aufzurufen.

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"

Der folgende Code zeigt die Funktion tf_install_in_cloud_build_step, die in bash_utils.sh definiert ist. Die Build-Konfigurationsdateien rufen diese Funktion auf, um Terraform spontan zu installieren. Es wird ein Cloud Storage-Bucket erstellt, um den Terraform-Status aufzuzeichnen.

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

Das folgende Code-Snippet zeigt die Funktion tf_apply, die in bash_utils.sh definiert ist. Zuerst wird terraform init aufgerufen, das alle Module und benutzerdefinierten Bibliotheken lädt. Anschließend wird terraform apply ausgeführt, um die Variablen aus der Datei main.tfvars zu laden.

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

Das folgende Code-Snippet zeigt die Funktion describe_deployment, die in bash_utils.sh definiert ist. Sie verwendet gcloud compute addresses describe, um die IP-Adressen der Load-Balancer anhand des Namens abzurufen, und gibt sie aus.

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

Das folgende Code-Snippet zeigt die Funktion tf_destroy, die in bash_utils.sh definiert ist. Er ruft terraform init auf, der alle Module und benutzerdefinierten Bibliotheken lädt, und führt dann terraform destroy aus, das die Terraform-Variablen entlädt.

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

Terraform-Vorlagen

Sie finden alle Terraform-Konfigurationsdateien und -variablen im Ordner copy-of-gcp-mig-simple/infra/.

  • main.tf: Das ist die Terraform-Konfigurationsdatei.
  • main.tfvars: Diese Datei definiert die Terraform-Variablen.
  • mig/ und splitter/: Diese Ordner enthalten die Module, die die Load-Balancer definieren. Der Ordner mig/ enthält die Terraform-Konfigurationsdatei, die die MIG für die blauen und grünen Load-Balancer definiert. Die blauen und grünen MIGs sind identisch. Daher werden sie einmal definiert und für die blauen und grünen Objekte instanziiert. Die Terraform-Konfigurationsdatei für den Splitter-Load-Balancer befindet sich im Ordner splitter/ .

Das folgende Code-Snippet zeigt den Inhalt von infra/main.tfvars. Es enthält drei Variablen: zwei, die bestimmen, welche Anwendungsversion in den blauen und den grünen Pools bereitgestellt werden soll, und eine Variable für die aktive Farbe: Blau oder Grün. Änderungen an dieser Datei lösen die Bereitstellung aus.

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

Im Folgenden finden Sie ein Code-Snippet aus infra/main.tf. Dabei gilt:

  • Für das Google Cloud-Projekt ist eine Variable definiert.
  • Google ist als Terraform-Anbieter festgelegt.
  • Für den Namespace ist eine Variable definiert. Allen von Terraform erstellten Objekten wird diese Variable vorangestellt, sodass mehrere Versionen der Anwendung im selben Projekt bereitgestellt werden können und die Objektnamen sich nicht überschneiden.
  • Die Variablen MIG_VER_BLUE, MIG_VER_BLUE und MIG_ACTIVE_COLOR sind die Bindungen für die Variablen in der Datei 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)."
}

Das folgende Code-Snippet aus infra/main.tf zeigt die Instanziierung des Splitter-Moduls. Dieses Modul verwendet die aktive Farbe, damit der Splitter-Load-Balancer weiß, welche MIG die Anwendung bereitstellen soll.

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
}

Das folgende Code-Snippet aus infra/main.tf definiert zwei identische Module für blaue und grüne MIGs. Er nimmt die Farbe, das Netzwerk und das Subnetzwerk an, die im Splitter-Modul definiert sind.

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
}

Die Datei splitter/main.tf definiert die Objekte, die für die Splitter-MIG erstellt werden. Das folgende Code-Snippet aus splitter/main.tf enthält die Logik zum Wechseln zwischen der grünen und der blauen MIG. Sie wird vom Dienst google_compute_region_backend_service unterstützt, der Traffic an zwei Back-End-Regionen weiterleiten kann: var.instance_group_blue oder var.instance_group_green. capacity_scaler definiert, wie viel Verkehr auf der Route verlaufen soll.

Mit dem folgenden Code werden 100% des Traffics an die angegebene Farbe weitergeleitet. Sie können diesen Code jedoch für das Canary-Deployment aktualisieren, um den Traffic an eine Teilmenge der Nutzer weiterzuleiten.

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

Die Datei mig/main.tf definiert die Objekte, die zu den blauen und den grünen MIGs gehören. Das folgende Code-Snippet aus dieser Datei definiert die Compute Engine-Instanzvorlage, die zum Erstellen der VM-Pools verwendet wird. In dieser Instanzvorlage ist das Terraform-Lebenszyklusattribut auf create_before_destroy festgelegt. Das liegt daran, dass Sie beim Aktualisieren der Version des Pools die Vorlage nicht zum Erstellen der neuen Version der Pools verwenden können, wenn sie noch von der vorherigen Version des Pools verwendet wird. Wenn jedoch die ältere Version des Pools gelöscht wird, bevor die neue Vorlage erstellt wird, sind die Pools eine bestimmte Zeit lang nicht verfügbar. Um dieses Szenario zu vermeiden, legen wir den Terraform-Lebenszyklus auf create_before_destroy fest. Damit wird die neuere Version eines VM-Pools erstellt, bevor die ältere Version gelöscht wird.

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

Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, löschen Sie entweder das Projekt, das die Ressourcen enthält, oder Sie behalten das Projekt und löschen die einzelnen Ressourcen.

Einzelne Ressourcen löschen

  1. Löschen Sie die Compute Engine-Ressourcen, die mit dem Trigger zum Anwenden erstellt wurden:

    1. Öffnen Sie die Cloud Build-Seite Trigger:

      Zur Seite "Trigger"

    2. Suchen Sie in der Tabelle Trigger die Zeile, die dem Zerstörer-Trigger entspricht, und klicken Sie auf Ausführen. Wenn die Ausführung des Triggers abgeschlossen ist, werden die vom apply-Trigger erstellten Ressourcen gelöscht.

  2. Löschen Sie die während des Bootstrapping erstellten Ressourcen. Führen Sie dazu den folgenden Befehl in Ihrem Terminalfenster aus:

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

Projekt löschen

    Google Cloud-Projekt löschen:

    gcloud projects delete PROJECT_ID

Nächste Schritte