Compute Engine にデプロイ


このガイドでは、Cloud Build と Terraform を使用して Compute Engine マネージド インスタンス グループ(MIG)でダウンタイムなしの Blue/Green デプロイを行う方法について説明します。

Cloud Build を使用すると、さまざまな Google Cloud ランタイム(Compute Engine、Google Kubernetes EngineGKE EnterpriseCloud Functions など)へのアプリケーションのビルドとデプロイなど、さまざまなデベロッパー プロセスを自動化できます。

Compute Engine MIG を使用すると、複数の同じ仮想マシン(VM)でアプリケーションを操作できます。自動スケーリング、自動修復、リージョン(マルチゾーン)デプロイ、自動更新などの自動化 MIG サービスを活用することで、ワークロードのスケーラビリティと高可用性を実現できます。Blue/Green 継続的デプロイモデルを使用して、ユーザー トラフィックを、ある MIG(Blue)から別の MIG(Green)に段階的に転送する方法について学習します。MIG は、どちらも本番環境で実行されます。

デザインの概要

次の図では、このドキュメントで説明するコードサンプルで使用される Blue / Green デプロイモデルを示します。

Blue/Green モデル

大まかに表現すると、このモデルには、次のコンポーネントが含まれています。

  • 2 つの Compute Engine VM プール: Blue と Green。
  • 3 つの外部 HTTP(S) ロードバランサ:
    • Blue/Green ロードバランサ。エンドユーザーから VM インスタンスの Blue または Green プールにトラフィックを転送します。
    • QA エンジニアとデベロッパーから Blue VM インスタンス プールにトラフィックを転送する Blue ロードバランサ。
    • QA エンジニアとデベロッパーから Green インスタンス プールにトラフィックを転送する Green ロードバランサ。
  • 次の 2 セットのユーザー:
    • Blue/Green ロードバランサにアクセスできるエンドユーザー。Blue または Green のインスタンス プールを参照します。
    • 開発とテストを目的として、両方のプールセットにアクセスする必要がある QA エンジニアとデベロッパー。Blue ロードバランサと Green ロードバランサの両方にアクセスでき、ロードバランサはそれぞれ Blue インスタンス プールと Green インスタンス プールに転送されます。

Blue と Green の VM プールは Compute Engine MIG として実装され、外部 IP アドレスは、外部 HTTP(S) ロードバランサを使用して MIG の VM に転送されます。このドキュメントで説明するコードサンプルでは、Terraform を使用してこのインフラストラクチャを構成します。

次の図では、デプロイで発生するデベロッパー オペレーションを示します。

デベロッパー オペレーション フロー

上の図では、赤い矢印はデプロイメント インフラストラクチャを初めて設定するときに発生するブートストラップ フローを表し、青い矢印はすべてのデプロイ中に発生する GitOps のフローを表しています。

このインフラストラクチャを設定するには、ブートストラップ プロセスを開始して GitOps フローのコンポーネントを設定するセットアップ スクリプトを実行します。

セットアップ スクリプトは、次のオペレーションを実行する Cloud Build パイプラインを実行します。

  • Cloud Source Repositoriescopy-of-gcp-mig-simple という名前のリポジトリを作成し、GitHub サンプル リポジトリから Cloud Source Repositories にあるこのリポジトリにソースコードをコピーします。
  • applydestroy という 2 つの Cloud Build トリガーを作成します。

apply トリガーは、Cloud Source Repositories 内の main.tfvars という名前の Terraform ファイルにアタッチされています。このファイルには、Blue ロードバランサと Green ロードバランサを表す Terraform 変数が含まれています。

デプロイを設定するには、main.tfvars ファイルの変数を更新します。apply トリガーは、tf_apply を実行して次のオペレーションを行う Cloud Build パイプラインを実行します。

  • 2 つの Compute Engine MIG(1 つは Green、もう 1 つは Blue)、4 つの Compute Engine VM インスタンス(2 つの Green MIG と 2 つの Blue MIG)、3 つのロードバランサ(Blue、Green、スプリッターなど)と 3 つのパブリック IP アドレス。
  • デプロイされたアプリケーションを Blue インスタンスと Green インスタンスで表示するために使用できる IP アドレスを出力します。

破棄トリガーは手動でトリガーされ、適用トリガーによって作成されたすべてのリソースが削除されます。

目標

  • Cloud Build と Terraform を使用して、Compute Engine VM インスタンス グループのバックエンドで外部 HTTP(S) ロードバランサを設定します。

  • VM インスタンスで Blue/Green デプロイを実行します。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud CLI をインストールします。
  3. gcloud CLI を初期化するには:

    gcloud init
  4. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  5. Google Cloud プロジェクトで課金が有効になっていることを確認します

  6. Google Cloud CLI をインストールします。
  7. gcloud CLI を初期化するには:

    gcloud init
  8. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  9. Google Cloud プロジェクトで課金が有効になっていることを確認します

試してみる

  1. Google コードサンプル リポジトリから設定スクリプトを実行します。

    bash <(curl https://raw.githubusercontent.com/GoogleCloudPlatform/cloud-build-samples/main/mig-blue-green/setup.sh)
    
  2. セットアップ スクリプトでユーザーの同意を求められたら、「yes」と入力します。

    スクリプトの実行は、数秒で完了します。

  3. Google Cloud コンソールで、Cloud Build の [ビルド履歴] ページを開きます。

    [ビルド履歴] ページを開く

  4. 最新のビルドをクリックします。

    [ビルドの詳細] ページが開き、3 つのビルドステップを含む Cloud Build パイプラインが表示されます。最初のビルドステップで、Cloud Source Repositories にリポジトリが作成されます。2 番目のステップでは、GitHub のサンプル リポジトリの内容のクローンを Cloud Source Repositories に作成します。3 番目のステップでは 2 つのビルドトリガーを追加します。

  5. Cloud Source Repositories を開く

    Cloud Source Repositories を開く

  6. リポジトリ リストで copy-of-gcp-mig-simple をクリックします。

    ページの下部にある [履歴] タブでは、copy-of-gcp-mig-simple という名前のリポジトリを作成するために Cloud Build が作成した説明 A copy of https://github.com/GoogleCloudPlatform/cloud-build-samples.git を含む 1 つの commit が表示されます。

  7. Cloud Build の [トリガー] ページを開きます。

    [トリガー] ページを開く

  8. applydestroy という名前の 2 つのビルドトリガーが表示されます。apply トリガーは main ブランチの infra/main.tfvars ファイルにアタッチされています。このトリガーは、ファイルが更新されるたびに実行されます。destroy トリガーは手動トリガーです。

  9. デプロイ プロセスを開始するには、infra/main.tfvars ファイルを更新します。

    1. ターミナル ウィンドウで、deploy-compute-engine という名前のフォルダを作成し、そのフォルダに移動します。

      mkdir ~/deploy-compute-engine
      cd ~/deploy-compute-engine
      
    2. copy-of-gcp-mig-simple リポジトリのクローンを作成します。

      gcloud source repos clone copy-of-mig-blue-green
      
    3. クローン作成したディレクトリに移動します。

      cd ./copy-of-mig-blue-green
      
    4. infra/main.tfvars を更新して、Blue を Green に置き換えます。

      sed -i'' -e 's/blue/green/g' infra/main.tfvars
      
    5. 更新したファイルを追加します。

      git add .
      
    6. ファイルを commit します。

      git commit -m "Promote green"
      
    7. ファイルを push します。

      git push
      

      infra/main.tfvars を変更すると、apply トリガーの実行がトリガーされ、デプロイが開始されます。

  10. Cloud Source Repositories を開く

    Cloud Source Repositories を開く

  11. リポジトリ リストで copy-of-gcp-mig-simple をクリックします。

    ページの下部にある [履歴] タブに、Promote green と記述された commit が表示されます。

  12. apply トリガーの実行を表示するには、Google Cloud コンソールの [ビルド履歴] ページを開きます。

    [ビルド履歴] ページを開く

  13. 最初のビルドをクリックして、[ビルドの詳細] ページを開きます。

    2 つのビルドステップを含む apply トリガー パイプラインが表示されます。最初のビルドステップでは、Terraform apply を実行して、Compute Engine とデプロイのロード バランシング リソースを作成します。2 番目のビルドステップでは、アプリケーションが実行されている IP アドレスを出力します。

  14. ブラウザで、Green MIG に対応する IP アドレスを開きます。デプロイを示す、次のようなスクリーンショットが表示されます。

    デプロイメント

  15. Compute Engine の [インスタンス グループ] ページに移動して、Blue と Green のインスタンス グループを表示します。

    [インスタンス グループ] ページを開く

  16. [VM インスタンス] ページを開き、4 つの VM インスタンスを確認します。

    [VM インスタンス] ページを開く

  17. [外部 IP アドレス] ページを開き、3 つのロードバランサを確認します。

    [外部 IP アドレス] ページを開く

コードについて

このコードサンプルのソースコードには以下が含まれます。

  • セットアップ スクリプトに関連するソースコード。
  • Cloud Build パイプラインに関連するソースコード。
  • Terraform テンプレートに関連するソースコード。

セットアップ スクリプト

setup.sh が、ブートストラップ プロセスを実行して Blue/Green デプロイのコンポーネントを作成するセットアップ スクリプトです。このスクリプトは、次の操作を実行します。

  • Cloud Build、Resource Manager、Compute Engine、Cloud Source Repositories API を有効にします。
  • プロジェクトの Cloud Build サービス アカウントに roles/editor IAM ロールを付与します。このロールは、Cloud Build でデプロイに必要な GitOps コンポーネントを作成して設定するために必要です。
  • プロジェクトの Cloud Build サービス アカウントに roles/source.admin IAM ロールを付与します。このロールは、Cloud Build サービス アカウントがプロジェクトに Cloud Source Repositories を作成し、サンプル GitHub リポジトリの内容を Cloud Source Repositories にクローン作成するために必要です。
  • 次のように、bootstrap.cloudbuild.yaml という名前の Cloud Build パイプラインをインラインで生成します。

    • Cloud Source Repositories に新しいリポジトリを作成します。
    • サンプル GitHub リポジトリから Cloud Source Repositories の新しいリポジトリにソースコードをコピーします。
    • 適用ビルドトリガーと破棄ビルドトリガーを作成します。
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 パイプライン

apply.cloudbuild.yamldestroy.cloudbuild.yaml は、セットアップ スクリプトが GitOps フローのリソースを設定するために使用する Cloud Build 構成ファイルです。apply.cloudbuild.yaml には、2 つのビルドステップがあります。

  • 関数 tf_install_in_cloud_build_step を呼び出す tf_apply build ビルドステップ。これにより、Terraform がインストールされます。tf_apply は、GitOps フローで使用されるリソースを作成します。関数 tf_install_in_cloud_build_steptf_applybash_utils.sh で定義されており、ビルドステップでは source コマンドを使用してこれらの関数を呼び出します。
  • ロードバランサの IP アドレスを出力する describe_deployment 関数を呼び出す describe_deployment ビルドステップ。

destroy.cloudbuild.yaml は、tf_apply によって作成されたすべてのリソースを削除する tf_destroy を呼び出します。

関数 tf_install_in_cloud_build_steptf_applydescribe_deploymenttf_destroy は、bash_utils.sh ファイルで定義されています。ビルド構成ファイルは、source コマンドを使用して関数を呼び出します。

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"

次のコードでは、bash_utils.sh で定義されている関数 tf_install_in_cloud_build_step を示します。ビルド構成ファイルがこの関数を呼び出して、Terraform をその場でインストールします。Terraform のステータスを記録する Cloud Storage バケットが作成されます。

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

次のコード スニペットでは、bash_utils.sh で定義されている関数 tf_apply を示します。まず、すべてのモジュールとカスタム ライブラリを読み込む terraform init を呼び出してから、terraform apply を実行して 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"
}

次のコード スニペットでは、bash_utils.sh で定義されている関数 describe_deployment を示します。gcloud compute addresses describe を使用し、名前でロードバランサの IP アドレスを取得して出力します。

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

次のコード スニペットでは、bash_utils.sh で定義されている関数 tf_destroy を示します。すべてのモジュールとカスタム ライブラリを読み込む terraform init を呼び出して、Terraform 変数をアンロードする terraform destroy を実行します。

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 テンプレート

すべての Terraform 構成ファイルと変数は、copy-of-gcp-mig-simple/infra/ フォルダにあります。

  • main.tf: Terraform 構成ファイルです。
  • main.tfvars: このファイルでは Terraform 変数を定義します。
  • mig/splitter/: これらのフォルダには、ロードバランサを定義するモジュールが含まれています。mig/ フォルダには、Blue ロードバランサと Green ロードバランサの MIG を定義する Terraform 構成ファイルが含まれています。Blue MIG と Green MIG は、同じであるため、Blue オブジェクトと Green オブジェクト用に 1 回定義され、インスタンス化されます。スプリッター ロードバランサの Terraform 構成ファイルは、splitter/ フォルダにあります。

次のコード スニペットでは、infra/main.tfvars の内容を示します。これには、Blue プールと Green プールにデプロイするアプリケーションのバージョンを決定する 2 つの変数と、アクティブな色(Blue または Green)の変数が含まれます。このファイルを変更すると、デプロイがトリガーされます。

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

infra/main.tf のコード スニペットを次に示します。このスニペットでは:

  • Google Cloud プロジェクト用に変数が定義されます。
  • Google は Terraform プロバイダとして設定されます。
  • 名前空間用に変数が定義されます。Terraform で作成したすべてのオブジェクトには、この接頭辞が付けられるため、アプリケーションの複数のバージョンを同じプロジェクトにデプロイでき、オブジェクト名は互いに競合しません。
  • 変数 MIG_VER_BLUEMIG_VER_BLUEMIG_ACTIVE_COLOR は、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)."
}

infra/main.tf の次のコード スニペットでは、スプリッター モジュールのインスタンス化を示します。このモジュールは、分配ロードバランサがアプリケーションをデプロイする MIG を認識できるように、アクティブ カラーを取得します。

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
}

次に示す infra/main.tf のコード スニペットでは、Blue MIG と Green MIG に対する 2 つの同じモジュールを定義します。これはスプリッター モジュールで定義されたカラー、ネットワーク、サブネットワークを取得します。

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
}

ファイル splitter/main.tf では、スプリッター MIG 用に作成されるオブジェクトを定義します。splitter/main.tf のコード スニペットを次に示します。これには、Green MIG と Blue MIG を切り替えるロジックが含まれています。これは google_compute_region_backend_service サービスを基盤としており、var.instance_group_blue または var.instance_group_green の 2 つのバックエンド リージョンにトラフィックを転送できます。capacity_scaler では、転送するトラフィックの量を定義します。

次のコードでは、トラフィックの 100% が指定された色に転送されますが、このコードをカナリア デプロイで更新して、そのトラフィックをユーザーのサブセットに転送できます。

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

ファイル mig/main.tf では、Blue MIG と Green MIG に関連するオブジェクトが定義されています。このファイルの次のコード スニペットでは、VM プールの作成に使用される Compute Engine インスタンス テンプレートを定義します。このインスタンス テンプレートでは、Terraform ライフサイクル プロパティが create_before_destroy に設定されます。これはプールのバージョンを更新する際、テンプレートが以前のバージョンのプールでまだ使用されている場合に、そのテンプレートで新しいバージョンのプールを作成できないためです。ただし、新しいテンプレートを作成する前に古いバージョンのプールが破棄された場合、プールがダウンする期間があります。この状況を回避するために、Terraform のライフサイクルを create_before_destroy に設定して、古いバージョンが破棄される前に新しいバージョンの VM プールが作成されるようにします。

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

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

リソースを個別に削除する

  1. 適用トリガーによって作成された Compute Engine リソースを削除します。

    1. Cloud Build の [トリガー] ページを開きます。

      [トリガー] ページを開く

    2. [トリガー] テーブルで、destroy トリガーに対応する行を見つけて、[実行] をクリックします。トリガーの実行が完了すると、apply トリガーによって作成されたリソースが削除されます。

  2. ターミナル ウィンドウで次のコマンドを実行して、ブートストラップ中に作成されたリソースを削除します。

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

プロジェクトの削除

    Google Cloud プロジェクトを削除します。

    gcloud projects delete PROJECT_ID

次のステップ