🦔

Terraform を使って Google Cloud のリソースを管理することはじめ(gloud authを利用)

8 min read

Google Cloud のリソースを管理するツールのひとつに、Terraformがあります。よくタッグが組まれますが、私が最初何もわからない状態から触ろうとしたとき、リソースをデプロイするまで苦労しました。ので、振り返りも兼ねて記録を残します。

  • gcloud コマンドをインストールしてGoogle Cloudのクレデンシャルを作成できるようにする
  • Terraform 状態管理のための Cloud Storage バケットを作成する
  • Terraform を初期化してリソースをデプロイする

この流れで進めます。

gcloud コマンドのインストール

gloud コマンドをローカルへインストールします。このコマンドは、ローカルマシンと Google Cloud のプロジェクトをつなぎ、クレデンシャルを生成するために使います。また、Terraformの状態を管理するための Cloud Storage バケットを作成するのに使います。

https://cloud.google.com/sdk/docs/install#mac

筆者の環境はmacOSです。こちらのドキュメントを参考に環境に合わせてインストールしてください。

Google Cloud プロジェクトを作成、クレデンシャル生成

まだ Google Cloud のプロジェクトがなければ、作成してください。

https://cloud.google.com/resource-manager/docs/creating-managing-projects?hl=ja&visit_id=637777473487683584-3940004913&rd=1#creating_a_project

Google Cloudのプロジェクトを作成したら、クレデンシャルを作成する準備を進めます。クレデンシャルはローカルマシンから Googole Cloud に接続するため必要になるのですが、大きく分けて2種類の取得方法があります。

  1. Google Cloud でサービスアカウントを作り、そのクレデンシャルをダウンロードする
  2. Google Cloud のプロジェクトを作成したユーザーアカウント(@gmail.com)を使ってクレデンシャルを作る

ここでは2番目の方法で進めます。

ユーザーアカウントに紐づく権限は大きくなりがちですので取り扱いに注意してください。

まず、gcloudのコンフィグを設定します。次のコマンドを実行してください。

gcloud config configurations create <任意ですが、作成したプロジェクト名が無難>

# 例
gcloud config configurations create graphql-training
Created [graphql-training].
Activated [graphql-training].

次に、作成したプロファイルにアカウント名とプロジェクト名を設定します。

gcloud config set core/account <Google Cloud のログインに使ったメアド>
gcloud config set core/project <Google Cloud のプロジェクト名>

# 例
gcloud config set core/account test@example.com
gcloud config set core/project graphql-training

この操作により、gcloud コマンドの状態がアップデートされ、コンフィグとしてプロジェクト名とアカウント名がセットされました。ここから、「ログイン」操作を行うことにより、ローカルマシンにクレデンシャル情報が作成されます。次のコマンドを入力してください。

gcloud auth login 

するとブラウザが開き、認証を求められます。対応する Google Cloud のアカウントを選んだ上で、連携を許可してください。これで、ローカルマシンにクレデンシャルが生成されます。場所は~/.config/gcloud/credentials.dbです。このクレデンシャルはローカルマシンで次のようなコマンドライン実行時に使われます。

  • gcloud
  • bq # BigQuery のCLI
  • gsutil # Cloud Storage のCLI

さらにもうひとつ認証処理を行ってください。

gcloud auth application-default login

こちらもやはりブラウザが開き、認証を求められます。連携を許可すると、ローカルマシンに別のクレデンシャルが生成されます。場所は~/.config/gcloud/application_default_credentials.json.dbです。このクレデンシャルは Google Cloud のSDKを使ったプログラムを実行する際の認証に利用します。Terraformもこのファイルを使います。

これでローカルマシンから作成した Google Project に対していろいろ操作する準備ができました。

Terraform 状態管理のためのバケット作成

Terraform は Google Cloud 上に作成したリソースの状態を tfstate というファイルで管理して差分を検出しています。もちろんtfstateをローカルで持っておくこともできるのですが、複数人の開発ではこのファイルをクラウドストレージで管理することで競合を防げます。Google Cloud の場合は共有ストレージとして Cloud Storage が使えますので、ここで状態管理するようにしましょう。というわけで早速バケットを作ります。gsutilコマンドを使いますのでこちらもインストールしてください。

https://cloud.google.com/storage/docs/gsutil_install?hl=ja

その後、状態管理のためのバケットを作成します。

gsutil mb gs://<任意のバケット名>

# 例:
gsutil mb gs://graphql-training-artifacts

mb は make bucket ですね(多分)。準備OKです。

Terraform 初期化

ここまでできたら Terraform が使えます。Terraform は、もちろんインストールして使ってもいいのですが、Dockerコンテナも提供されているのでそれを使えばインストールいらずです。次のようなbashファイルを作ってください。

tf.sh
#!/bin/bash

command=${@:1} 

docker run -it --rm \
  -v $PWD:/work \
  -v $HOME/.config/gcloud:/.config/gcloud \
  -w /work \
  -e GOOGLE_APPLICATION_CREDENTIALS=/.config/gcloud/application_default_credentials.json \
  --entrypoint "/bin/sh" \
  hashicorp/terraform:latest \
  -c "terraform $command"

hashicorp/terraform というコンテナを使って terraform コマンドを実行しています。先ほどローカルマシンで作ったクレデンシャルもわたしていますね。ではTerraformのリソースを定義します。次のファイルを作ります。

main.tf
terraform {
  required_version = "~> 1.0.0"
  backend "gcs" {
    prefix = "tfstate/v1"
  }
}

## project ##
provider "google" {
  project = var.gcp_project_id
  region  = var.primary_region
}

このファイルはまだリソースを作成しませんが、一度動作確認しましょう。

chmod +x tf.sh
./tf.sh init -backend-config="bucket=<gsutilで作ったバケット>"

# 例:
./tf.sh init -backend-config="bucket=graphql-training-artifacts"

---
Initializing the backend...

Successfully configured the backend "gcs"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding latest version of hashicorp/google-beta...
- Finding latest version of hashicorp/google...
- Installing hashicorp/google-beta v4.6.0...

このように表示されれば成功です。ブラウザで Google Cloud Storage の graphql-training-artifacts/tfstate/v1 を覗いてみてください。状態管理ファイルである default.tfstate が作成されているはずです。

Artifact Repository のリポジトリを作ってみる

ここまでできればあとはリソース作りたい放題です。なんでもいいのですが、Artifact Registry のリポジトリを作ってみましょう。modules/artifact-registry.tfファイルを作ります。

tree
.
├── README.md
├── main.tf
├── modules
│   └── artifact-registry
│       └── artifact-registry.tf
└── tf.sh
modules/artifact-registry/artifact-registry.tf
variable "gcp_project_id" {}
variable "artifact_registry_location" {
  type = string
  # https://cloud.google.com/storage/docs/locations
  description = "Artifact Registry のロケーションをどこにするか"
}

# バックエンドアプリケーション用の Artifact Registry リポジトリ
resource "google_artifact_registry_repository" "backend" {
  provider = google-beta

  project       = var.gcp_project_id
  location      = var.artifact_registry_location
  repository_id = "backend"
  description   = "バックエンドアプリケーション"
  format        = "DOCKER"
}

main.tf も修正します。

main.tf
# Cloud Run のデプロイで利用するArtifact Registry のリポジトリ
+module "artifact-registry" {
+  source                     = "./modules/artifact-registry"
+  gcp_project_id             = var.gcp_project_id
+  artifact_registry_location = var.primary_region
+}

さきほどから、var.xxxxみたいなやつが登場してますね。お察しの通りTerraformで扱える変数です。この仕組みを上手く使うことで、公開したくない情報、外部から注入したい情報をリソース構成に組み込めます。値を注入するために、variable.tfファイルを新しく作ってください。

variable.tf
variable "gcp_project_id" {}
variable "primary_region" {}

このファイルを定義することで var.gcp_project_id のようにリソース定義のなかで呼び出せます。では、実際の値はどのように注入するのでしょうか。いくつか方法があるようですが、ここでは「terraform.tfvarsファイルをつくり、このファイルはバージョン管理しない」方針をとります。

https://www.terraform.io/language/values/variables#variable-definitions-tfvars-files
terraform.tfvars
gcp_project_id    = "gql-training"
primary_region    = "us-central1"

このくらいであれば別にバージョン管理しても良いのでは?と思うかもしれませんが、開発をすすめるうちに外部APIキーだったり、パスワードだったりを管理することもでてきます。秘匿情報は、たとえばですが Secrets Manager や 1Password で管理しておき、開発メンバーにterraform.tfvarsを共有することで事故を防げます。

さて、注入する変数の値もセットしたところで、initplanを実行してみましょう。これらコマンドではまだリソースは作成されません。

./tf.sh init

Initializing modules...
- artifact-registry in modules/artifact-registry

moduleを新しく定義した場合、改めてinitが必要になります。

./tf.sh plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.artifact-registry.google_artifact_registry_repository.backend will be created
  + resource "google_artifact_registry_repository" "backend" {
      + create_time   = (known after apply)
      + description   = "バックエンドアプリケーション"
      + format        = "DOCKER"
      + id            = (known after apply)
      + location      = "us-central1"
      + name          = (known after apply)
      + project       = "xxxxxxx"
      + repository_id = "backend"
      + update_time   = (known after apply)
    }

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

このように表示されるはずです。意図したとおりの作成プランになっているようでしたら、実際に適用するコマンドを打ちます。

./tf.sh apply

もしかするとここで「APIを有効にしてね」というエラーが出るかもしれません。Google Cloud は、リソースを作成したり更新できる Web API を用意してくれているのですが、デフォルトでは無効になっているものもあります。Terraform はそんなAPIを使ってリソースを管理しているため、モノによってはAPIを有効にしないと作れないものもあります。ガイドに従い、ブラウザからAPIを有効にしてあげればOKです。その後、再度実行してください。

./tf.sh apply

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

このようなメッセージがでればOKです。最後にArtifact Registryをブラウザで表示して、リソースが作成されていることを確認してください。

まとめ

お疲れさまでした。Terraform をつかって Google Cloud のリソースを作成してみました。Google Cloud の認証作法や Terraform の状態管理で準備する箇所がありますが、そこさえクリアしてしまえば快適にリソースを管理できます。ぜひおためしください。

ソースコード

この記事で紹介したソースコードは以下のリポジトリで公開しています。

https://github.com/cm-wada-yusuke/gql-nest-prisma-training/tree/main/google-cloud-terraform

この記事に贈られたバッジ

Discussion

ログインするとコメントできます