Google Cloud PlatformリソースをCDK for Terraformでデプロイしてみた

Google Cloud PlatformリソースをCDK for Terraformを使ってデプロイしてみます。 まずは環境をセットアップして、シンプルなデプロイを試します。
2023.08.22

CX事業部Delivery部の新澤です。

Google Cloud Platform(GCP)のリソースをデプロイするために、CDK for Terraform(CDKTF)を試してみました。

もちろんTerraform単体でもリソースの管理・デプロイは可能なのですが、書き慣れた開発言語でリソースを定義できるのはHCLに不慣れな自分にはかなり魅力的です。

今回は、初期セットアップとシンプルなCDKスタックを作成して、デプロイを試してみます。

検証環境

OS: Debian Linux 11 (VSCode DevContainersのNode.js & TypeScriptを利用)

言語: TypeScript

gcloud CLIのインストール・設定

まずGCPのCLIを利用できるようにします。

インストール

公式ドキュメントの手順にしたがってインストールします。

gcloud CLIの配布URLをパッケージソースに追加します。

$ echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main

Google Cloudの公開鍵をインポートします。

$ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -

gcloud CLIをインストールします。

$ sudo apt-get update && sudo apt-get install google-cloud-cli

確認してみます。

$ gcloud --version
Google Cloud SDK 443.0.0
alpha 2023.08.11
beta 2023.08.11
bq 2.0.96
bundled-python3-unix 3.9.16
core 2023.08.11
gcloud-crc32c 1.0.0
gsutil 5.25

大丈夫そうですね。

初期化

gcloud CLIの初期化を行います。

$ gcloud init
Welcome! This command will take you through the configuration of gcloud.

Your current configuration has been set to: [default]

You can skip diagnostics next time by using the following flag:
  gcloud init --skip-diagnostics

Network diagnostic detects and fixes local network connection issues.
Checking network connection...done.                                                                                                                                      
Reachability Check passed.
Network diagnostic passed (1/1 checks passed).

You must log in to continue. Would you like to log in (Y/n)?  y

Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=32555940559.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fsdk.cloud.google.com%2Fauthcode.html&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fsqlservice.login+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&state=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&prompt=consent&access_type=offline&code_challenge=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&code_challenge_method=S256

GCPにログインするためのURLが表示されるので、ブラウザでアクセスし、認証後に表示される認証コードを入力します。

Enter authorization code: <ブラウザで認証後に表示される認証コード>
You are logged in as: [xxxxxxxx@hoge.com].

プロジェクトを選択します。

Pick cloud project to use: 
 [1] my-project
 [2] Enter a project ID
 [3] Create a new project
Please enter numeric choice or text value (must exactly match list item):  1

Your current project has been set to: [my-project].

Terraform CLI

次はTerraform CLIをインストールします。

インストール

PGP署名をインストールします。

$ sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
$ wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint

HashiCorpのリポジトリを追加します。

$ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list

CLIをインストールします。

$ sudo apt update && sudo apt-get install terraform
$ terraform --version
Terraform v1.5.5
on linux_arm64

CDK for Terraform(CDKTF)

ようやくCDKTFまで辿り着きました。

インストール

CDKTF CLIをインストールします。

$ npm install --global cdktf-cli@latest
npm WARN deprecated @npmcli/ci-detect@1.4.0: this package has been deprecated, use `ci-info` instead

added 477 packages in 38s

98 packages are looking for funding
  run `npm fund` for details
$ cdktf --version
0.18.0

初期化

CDKTFの初期化を実行して、雛形を作成します。

providerにgoogleを指定すると、GCPのリソースを定義するためのコンストラクトが.genディレクトリに作成されます。

$ cdktf init --template=typescript --providers=google --local
Note: By supplying '--local' option you have chosen local storage mode for storing the state of your stack.
This means that your Terraform state file will be stored locally on disk in a file 'terraform.<STACK NAME>.tfstate' in the root of your project.
? Project Name cdktf-gcp-sample
? Project Description A simple getting started project for cdktf.
? Do you want to start from an existing Terraform project? no
? Do you want to send crash reports to the CDKTF team? Refer to 
https://developer.hashicorp.com/terraform/cdktf/create-and-deploy/configuration-file#enable-crash-reporting-for-the-cli for more information no

added 2 packages, and audited 57 packages in 3s

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

added 313 packages, and audited 370 packages in 24s

37 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
(略)
[2023-08-22T00:54:42.931] [INFO] default - Adding local provider registry.terraform.io/hashicorp/google with version constraint undefined to cdktf.json
Local providers have been updated. Running cdktf get to update...
Generated typescript constructs in the output directory: .gen

リモートバックエンド用バケットの作成

Terraformを利用する際には、リソースの状態を管理するtfstateファイルを管理する必要があります。

デフォルトではローカルにtfstateファイルが作成されますが、チーム開発の場合はAWS S3やGCP Cloud StorageといったストレージサービスやTerraform Cloudなどのリモートバックエンドと呼ばれる管理方法を選択することが多いです。

ここでは、Cloud Storageでリモートバックエンドを構成してみます。

gcloud CLIでバケットを作成します。

$ gcloud storage buckets create gs://tf-remote-backend-xxxxxxxx
Creating gs://tf-remote-backend-xxxxxxxx/...
$ gcloud storage ls
gs://tf-remote-backend-xxxxxxxx/

CDKの定義

ここではCloud Storageバケットを1つ作成するだけのシンプルなCDKスタックを作成してみます。

以下、全ソースコードです。

main.ts

import { Construct } from 'constructs';
import { App, GcsBackend, TerraformStack } from 'cdktf';
import * as google from './.gen/providers/google';

class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // GCPプロバイダー
    new google.provider.GoogleProvider(this, 'GoogleProvider', {
      project: 'my-project',
    });

    // リモートバックエンドをCloud Storageバケットで構成
    new GcsBackend(this, {
      bucket: 'tf-remote-backend-xxxxxxxx',
    });

    // バケット
    new google.storageBucket.StorageBucket(this, 'StorageBucket', {
      location: 'us-central1',
      name: 'mysample-bucket-xxxxxxxx',
    });
  }
}

const app = new App();
new MyStack(app, 'cdktf-gcp-sample');
app.synth();

GCPリソースを定義するために、CDKTFの初期化時に生成されたGCPコンストラクトを.genディレクトリからインポートします。

import * as google from './.gen/providers/google';

リモートバックエンドに先ほどCLIで作成したバケットを指定します。

new GcsBackend(this, {
  bucket: 'tf-remote-backend-xxxxxxxx',
});

デプロイ

CDKTF CLIで作成したCDKスタックのdiffを実行して、作成されるリソースを確認してみます。

初回実行時にはスタックで定義したリモートバックエンドの初期化も行われます。

$ cdktf diff

このとき以下の認証エラーが発生した場合は、gcloud CLIで認証を行います。

[2023-08-22T01:20:50.335] [ERROR] default - ╷
│ Error: Attempted to load application default credentials since neither `credentials` nor `access_token` was set in the provider block.  No credentials loaded. To use your gcloud credentials, run 'gcloud auth application-default login'

以下を実行して、gcloud CLIインストール時と同様に表示された認証URLにアクセスし、認証後に表示される認証コードを入力します。

$ gcloud auth application-default login

再度diffを実行してみます。

$ cdktf diff
cdktf-gcp-sample  Initializing the backend...
cdktf-gcp-sample
cdktf-gcp-sample  
                  Successfully configured the backend "gcs"! Terraform will automatically
                  use this backend unless the backend configuration changes.
cdktf-gcp-sample  Initializing provider plugins...
                  - Finding hashicorp/google versions matching "4.79.0"...
cdktf-gcp-sample  - Installing hashicorp/google v4.79.0...
cdktf-gcp-sample  - Installed hashicorp/google v4.79.0 (signed by HashiCorp)

                  Terraform has created a lock file .terraform.lock.hcl to record the provider
                  selections it made above. Include this file in your version control repository
                  so that Terraform can guarantee to make the same selections by default when
                  you run "terraform init" in the future.
cdktf-gcp-sample  Terraform has been successfully initialized!
                  
                  You may now begin working with Terraform. Try running "terraform plan" to see
                  any changes that are required for your infrastructure. All Terraform commands
                  should now work.

                  If you ever set or change modules or backend configuration for Terraform,
                  rerun this command to reinitialize your working directory. If you forget, other
                  commands will detect it and remind you to do so if necessary.
cdktf-gcp-sample  - Fetching hashicorp/google 4.79.0 for linux_amd64...
cdktf-gcp-sample  - Retrieved hashicorp/google 4.79.0 for linux_amd64 (signed by HashiCorp)
                  - Obtained hashicorp/google checksums for linux_amd64; Additional checksums for this platform are now tracked in the lock file
cdktf-gcp-sample  Success! Terraform has updated the lock file.

                  Review the changes in .terraform.lock.hcl and then commit to your
                  version control system to retain the new checksums.
cdktf-gcp-sample  Terraform used the selected providers to generate the following execution
                  plan. Resource actions are indicated with the following symbols:
cdktf-gcp-sample  + create

                  Terraform will perform the following actions:

                    # google_storage_bucket.StorageBucket (StorageBucket) will be created
                    + resource "google_storage_bucket" "StorageBucket" {
                        + force_destroy               = false
                        + id                          = (known after apply)
                        + labels                      = (known after apply)
                        + location                    = "US-CENTRAL1"
                        + name                        = "mysample-bucket-xxxxxxxx"
                        + project                     = (known after apply)
                        + public_access_prevention    = (known after apply)
                        + self_link                   = (known after apply)
                        + storage_class               = "STANDARD"
                        + uniform_bucket_level_access = (known after apply)
                        + url                         = (known after apply)
                      }

                  Plan: 1 to add, 0 to change, 0 to destroy.
                  
                  ─────────────────────────────────────────────────────────────────────────────

                  Saved the plan to: plan

                  To perform exactly these actions, run the following command to apply:
                      terraform apply "plan"

問題なくdiffが表示されたら、デプロイしてみます。

$ cdktf deploy
cdktf-gcp-sample  Initializing the backend...
cdktf-gcp-sample  Initializing provider plugins...
                  - Reusing previous version of hashicorp/google from the dependency lock file
cdktf-gcp-sample  - Using previously-installed hashicorp/google v4.79.0

                  Terraform has been successfully initialized!
(略)
cdktf-gcp-sample  google_storage_bucket.StorageBucket (StorageBucket): Creating...
cdktf-gcp-sample  google_storage_bucket.StorageBucket (StorageBucket): Creation complete after 3s [id=mysample-bucket-xxxxxxxx]
cdktf-gcp-sample  
                  Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

No outputs found.

$ gcloud storage ls
gs://mysample-bucket-xxxxxxxx/
gs://tf-remote-backend-xxxxxxxx/

スタックで定義したバケットが作成されました!

後片付け

スタックを削除します。

$ cdktf destroy

最後に

GCPを使うのは初めてだったのですが、CDKTFを使って慣れた開発言語で記述できたので、簡単にデプロイを試すことができました。

次はデータベースサービスやコンテナのデプロイを試してみたいと思います。