TerraformでCompute Engineのデプロイを自動化する - 基礎編
Google Workspace Migrateを使うに当たっては、Google Cloud上に何台ものCompute Engineの仮想環境を構築しセットアップする必要性があります。最大で1プロジェクト40台のノードサーバを手作業で構築しセットアップするのはとても大変。
ということで、これらの仮想マシンのデプロイをTerraformを使って自動化し、検証・再検証・先行ユーザ・本番ユーザといったような何回も手作業での構築時間の圧縮を図れるようにすると、コストも減るのでここにその手法と手順を記録する。
今回使用するツール
macOSでなくとも利用できますが、今回はmacOSのTerminal上で作業をし、利用するスクリプトについてはVSCodeを使って記述します。
テストの検証では、Linuxの仮想マシンを構築しますが、本来のGWMで使う仮想マシンはWindows Server 2019をもって構築する必要があります。
作業工程と事前準備
作業の流れ
構築の流れですが、Google Cloud側に事前にプロジェクトは用意されてる状態で進みます。このプロジェクトに対して作業を行いますが、Compute Engineの稼働時間がコストに跳ね返るので、Terraformのスクリプトを作成してから、作業に取り掛かることになります。
- main.tfというファイル(本体)をVSCodeで作成する
- ファイルのProvider設定はGoogleで行う
- ターミナルのコマンドでterraform initで初期化する.
- 手動でCompute Engine上で仮想マシンを作成しておく(検証時は最小構成で十分)
- 4.の仮想環境にRDPで接続してアプリをインストールしたりなどをしておく(検証時はファイル1個作成などでOK)
- 仮想マシンのディスクのスナップショットを取る(terraformはこのスナップショットからコピーする)
- ターミナルのコマンドでterraform importコマンドにて4.の仮想マシン設定を取り込む。
- ターミナルのコマンドでterraform applyにて4.の仮想マシンを必要台数分複製する(ここで1.のファイルが利用される)
この仕組みを利用することで、例えば40台分作成するに当たって、作成済みのマシンを除いて必要台数をコピーして作成してくれるのがTerraformの良い所。
よってmain.tfのファイルが最初に必要になるため、Compute Engineの作業はスクリプトを用意出来てからとなります。
※不要になったらスナップショットもお金が掛かるので削除しておきましょう。
Google Cloud側の準備
プロジェクト概要とCompute Engine API
この作業はmain.tfというファイルが用意出来て複製実行直前に行います。以下の手順でプロジェクトに対して、手動で1個複製元になるマシンを構築します。
- Google Cloud Consoleのトップページを開く
- 表示されてるプロジェクト番号とプロジェクトIDを後ほど利用するので控えておく。
- 次に左サイドバーからCompute Engineをクリックする
- APIを有効化しろと出てくるので、有効にするをクリックする
図:プロジェクト番号等を控えておく
サービスアカウントの作成も自動化する場合
今回は手動で作成したサービスアカウントを使うのでこのAPIは特に有効化しなくて良いですが、サービスアカウントの作成もTerraformで自動化することが可能です。その場合にはIdentity and Access Management (IAM) APIを有効化しないと、terraformでapplyした時にエラーとなります。
サービスアカウント作成自動化の場合は有効化しておきましょう。
図:有効化しないとエラーになる
図:API有効化
サービスアカウントを作成する
後述のgcloudコマンドでも作れますが、ここでは手作業で作っておきます。
- 左サイドバーよりIAMと管理を開き、サービスアカウントを開きます。
- 上部にあるサービスアカウントを作成をクリックする
- サービスアカウント名はterraformとでも入れて、説明を入れて作成して続行をクリック
- ロールでは、編集者を選択します。続行をクリックします。
- 3つ目の設定は特に何もせずにスルー。完了をクリックします。
- 「terraform@プロジェクト名.iam.gserviceaccount.com」というサービスアカウントが出来ました。アカウント名をクリックして中に入ります。
- 上部にあるキータブをクリックして、鍵を追加⇒新しい鍵を作成をクリックする
- キーのタイプはJSONのままで、作成をクリック。
- JSONファイルがダウンロードされるので、後述のローカルプロジェクトフォルダにでも入れておきます。
図:これでサービスアカウントが出来ました
IAMの権限付与
前述のサービスアカウント作成時のロールの付与にて、本来はIAMのパネルで対象のサービスアカウントが出てこないとオカシイです。しかし、お客様環境で自身に割り当てられてる権限がなく、IAMに登録されていないことがあります。このロールをつける権限は「Project IAM 管理者」を付けてもらう必要があります。
このままTerraformを実施すると、403エラーで動かないことになります。
この場合、IAMを操作できる権限の人に以下の作業をしてもらう必要があります。
-
IAMのパネルにて、アクセス権を付与をクリックする
-
プリンシパルネームはterraform用に作ったサービスアカウントの名前(terraform@project名.iam.gserviceaccount.comみたいなの)
-
ロールは「編集者」をつける
これで、terraform applyを実行しても403エラーにならずに実行することが出来るようになります。
図:403エラーが発生してしまった
図:編集者ロールが必要
VSCodeの準備
VSCodeでmain.tfなどのTerraformファイルを開けますが、より便利にする為に拡張機能をインストールしておきます。日本語化などの拡張機能も入れておくと良いでしょう。
- VSCodeを起動する
- 左サイドバーの拡張機能をクリックする
- 検索窓からTerraformと検索すると、Hashicorp製のものが見つかるので、installをクリックする
- ダイアログが出るので、ワークスペースを信頼してインストールをクリックする
これでVSCodeの準備は完了です。
図:VSCodeでデフォルトで開くようにしておく
図:拡張機能を入れておく
図:キレイに書くことが可能になる
Terraform環境の構築
Homebrewのインストール
macOSの様々なパッケージをインストールする「homebrew」。非常によく使うのでインストールします。今回のTerraformコマンドもこちらでインストールするほうが手っ取り早いです。
-
ターミナルを起動する
- 以下のコマンドを実行する。その際にユーザのmacへのログインパスワードを問われるので入力する。
1/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - installation successfulと出たら成功ですが、パスが通っていないので、以下の作業を続ける。ユーザ名の所は書き換えて実行が必要です。
123(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/ここにユーザ名/.zprofileeval "$(/opt/homebrew/bin/brew shellenv)"brew -v
これでbrewのバージョンが表示されたら成功 -
続けてterraformをインストールしましょう。
図:Homebrewをまず準備する
gcloud CLI をインストールする
ツールのインストール
TerraformだけだとGoogle Cloudにアクセス出来ないので、Google Cloud CLIをインストールします。
- こちらのページにアクセスしてmacOS版をダウンロードする(M1はARM64, Apple M1 siliconを選択)
- ダブルクリックして解凍する
- ターミナルを起動して、2.の解凍先のフォルダまで移動しておく
1cd Desktop/google-cloud-sdk - 中に入ってるinstall.shを実行する
1./install.sh
Do you want to help improve the Google Cloud CLIと問われるますが、「改善のために匿名の使用統計情報を送信するかどうか」なので、nでも問題ないです。 - Do you want to continue?と問われるので、Yと入力してEnterを実行
- Enter a path to an rc file to update, or leave blank to useと出ますが、blankのままEnterで問題ないです。
- Download and run Python 3.11 installer?と出るので、Yと入力してEnterを実行し、Pythonをインスコします。
- macOSのユーザパスワードを入力して続行します。
- 完了したら、一旦ターミナルは終了させておき、再度ターミナルを起動します(これをしないとgcloudコマンドが使えない)
- gcloud versionでバージョン表記が出たらオッケー
これでインストールが完了します。
もし、解凍先フォルダを他に移動してしまうとパスが通っていない状態なので、以下の作業をしなおしてパスを通し直す必要があります。
-
対象のフォルダをクリックした状態で、option + command + cでフルパスを取得できる
-
ターミナルを起動する
-
open ~/.zshrcを実行して設定ファイルを開く
-
ファイルが開かれるので、中に記述されてるGoogle Cloud SDKやshell command completion for gcloudに記述されてるパスを書き直す
-
上書き保存する
-
source ~/.zshrcで反映する
これで、gcloudコマンドが使えるようになります。
図:gcloud cliのインストールの様子
図:パスを通し直す場合
初期化しておく
続けて、ターミナル上でGoogle Cloudに接続し最初の認証作業を済ませておきます。
- ターミナルを起動する
- 以下のコマンドを実行する
1gcloud init - You must log in to continue. Would you like to log inと聞かれるのでYを入力してEnterを実行する
- Chromeが起動するので自身のGoogleアカウントにログインして認証を許可する
- This account has a lot of projects! Listing them all can take a whileと出るので、Enter a project IDを選択するので、1を入力する
- 続けて、プロジェクト番号を入力してEnterを実行する
これで初期化が完了しました。「gcloud auth application-default login」でも後から認証作業が可能です。
図:プロジェクト番号を入れて接続する
図:ログイン認証の様子
Terraformのインストール
ツールのインストール
まずは、Terraformをインストールします。公式ドキュメント通りに前述のHomebrewにてインストールをすることになります。
- ターミナルを起動する
- 以下のコマンドを実行する。
12brew tap hashicorp/tapbrew install hashicorp/tap/terraform - terraform -versionと実行してバージョン表示がでれば成功です。
図:Terraformのインストール
プロジェクトをローカルに作成する
ターミナルから以下のコマンドを実行してプロジェクトフォルダとmain.tfファイルを作成します。このmain.tfに対してコマンドを記述していくことになります。
これで書類フォルダ以下にプロジェクト用のフォルダが作成されて、空のmain.tfファイルが作成されます。
1 2 3 4 |
cd Documents mkdir gwm-project cd gwm-project touch main.tf |
gwm-projectは適当な名前でオッケーです。同じディレクトリに前述のサービスアカウントで作ってダウンロードしたJSONキーファイルを入れておくと良いでしょう。
図:プロジェクトにファイルが生成されました
Terraformスクリプトを書く
これでTerraformのスクリプトを書く準備が整いました。ここまでで用意した環境の値を元に構築していきます。
初期化作業
プロバイダの指定
まずは、初期化の為に必要なコードをmain.tfに書き込んでおきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# terraformの設定(v5以上を指定にしてみた) terraform { required_providers { google = { source = "hashicorp/google" version = "~> 5.0" } } } # terraformで利用するプロバイダーの指定 provider "google" { #サービスアカウントのJSONキーファイルを指定する credentials = file("./xxxx-hogehoge.json") #プロジェクトIDと構築先のリージョン指定 project = "プロジェクトIDをここに記入" region = "ここにリージョン名を入れる" zone = "ここにゾーンを指定する" } |
- サービスアカウント作成時のjsonファイルを使うので、上記のようにfileにて指定します。
- GCPのプロジェクトのIDをprojectに記入します。プロジェクト番号ではないので注意。
- regionはGCEをどのリージョンに作成するか?を指定する。今回は「us-central1」を指定。
- zoneを指定しなかった場合、同じリージョン内に勝手に作られます。今回は「us-central1-a」が指定されていました
zoneを指定せずに後述のImportを実行しようとすると「Cannot determine zone: set in this resource, or set provider-level zone」というエラーが出るので必ず指定しましょう。
Terraformの初期化
ここまで来たら、ターミナルからTerraformの初期化を実行します。
- ターミナルを起動する
- 作成しておいたTerraformのプロジェクトフォルダまで移動する
1cd Documents/gwm-project - 以下のコマンドを実行して初期化する
1terraform init - ターミナルで以下のコマンドを実行すると生成された2つのファイルが確認できます。
1ls -a - .terraformフォルダと .terraform.lock.hclが存在するのが確認できます。
生成されたファイルやフォルダはドットから始まる隠しファイル・フォルダなのでFinder上からは通常見えません。
図:プラグインとか色々ダウンロードされる
仮想マシンを作成する
Compute EngineでVMを作る
続けて、スナップショットを複製するコードを書く必要がありますが、その前にCompute Engine上でベースになる仮想マシンを1台作成してスナップショットを取ります。
今回は検証なので必要最低限のスペックのマシンを作成します。
- GCPの左サイドバーよりCompute Engineをクリックする
- インスタンスを作成をクリックする
- インスタンス名は適当に設定する(今回はgwmprj-20240813とでもしました)
- リージョンは「us-central1(アイオワ)」を選択します(後から変更出来ません)
- ゾーンはとりあえず指定なしで進めます。
- マシン構成は汎用ではE2を選択します。
- コンピューティング最適化ではC2を選択します。
- メモリ最適化ではM3を選択します。
- ストレージ最適化ではZ3しか選択できません。
- それぞれの項目に下の方にマシンプリセットがあるので最小のものを選んでいく。
- 下の方にあるブートディスクで警告が出てるので、変更をクリックする
- 右サイドバーが出てくるので、Debian GNU Linux 12のx86/64に変更する
- ディスクはとりあえず20GBくらいにしておく
- 選択をクリックする
- サービスアカウントは前述までに作っておいたterraform用のサービスアカウントを指定する
- 作成をクリックする
これで仮想マシンが作成されました。すでにVMは起動状態なので、必要なければ停止などをしておきましょう。IPなどは自動で割り当てがされています。
図:VMの設定
図:ブートディスクを変更
スナップショットを取得する
スナップショットのディスクを元に複製をするので、ここでスナップショットの作成を行います。
- GCEのトップ画面を開いておく
- 作成したVMの名前をクリックする
- 左サイドバーからストレージ項目にある「スナップショット」をクリックする
- スナップショットを作成をクリックする
- スナップショットの名前は適当にセットする。今回は snapshot-1とした(この名前をあとで使うので控えておく)
- スナップショットソースの種類では、ディスクを指定する
- ソースディスクではすでに作成したCompute Engineが出てくるのでそれを選択する
- タイプはスナップショットのままにしておく
- あとはデフォルトのままで、作成をクリックする
図:スナップショットを作成してる様子
Terraformにインポートする
GCE情報を追記する
作成したVMのインスタンス管理をTerraform管理下にする為にimportという作業を行います。main.tfに対して以下の内容を追記していく作業をします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# GCP側のサービスアカウント名の指定(サービスアカウントを作る場合) #resource "google_service_account" "default" { #account_id = "GCPのプロジェクト名を入れる" #display_name = "gwm_vm_instance" #} #Compute Engine用のリソースの設定 resource "google_compute_instance" "default" { #VMの設定 name = "ここにGCEのインスタンスの名前を入れる" machine_type = "作成時に指定したマシンタイプを入れる" zone = "ここにリージョンに割り当てられてるゾーンを指定する" allow_stopping_for_update = true #ブートディスクの指定 boot_disk { initialize_params { image = "debian-cloud/debian-12" size = 20 } } #ネットワーク設定 network_interface { network = "default" access_config { //テンポラリのグローバルIPがある場合 } } #割当サービスアカウントの指定 service_account { email = "terraform@プロジェクト名.iam.gserviceaccount.com" scopes = ["cloud-platform"] } } |
- service accout項目のaccount_idはGCPのプロジェクト名を入れる
- google_compute_instanceのnameは今回で言えば「gwmprj-20240813」を入力することになる。
- Machine typeも作成時に指定したものを入力(今回はc2-standard-4を選んでみてます)
- zoneは今回指定していませんが、自動で同じリージョンに割り当てられています(us-central1-aを入力しました)
- bootdiskは今回はDebian Gnu Linux 12なので、debian-cloud/debian-12と入力します。
- bootdiskでsizeを20で指定すると20GBのディスクサイズで作成します。
- allow_stopping_for_updateをtrueで指定すると、VMを停止して構成を強制変更許可します。
- IPアドレスは特にnetworkで指定していないので自動割り当てになります。
- 他は上記の設定のままで行きます。
インポートを実行する
今回の設定では前述までの間で
- Compute Engineリソース:google_compute_instanceのdefaultで作成してる
- name : 作成済みのインスタンス名は「gwmprj-20240813」である
この状態で、ローカルのTerraform側でImportを実行します。その場合のコマンドは以下のようになります。
1 |
terraform import google_compute_instance.default gwmprj-20240813 |
実行完了するとプロジェクトフォルダ内に「terraform.tfstate」というtfstateファイルが生成されます。複数名で共同で運用する場合は、これをCloud Storageなどにアップして参照するようにしますが、今回は個人利用なので、このままにしておきます。
図:TerraformでImportを実行してる様子
Terraformを実行する
ここまでで、Compute EngineにVMが無い状態であっても、指定のサービスアカウントを割り当てた状態でVMが作成可能です。また、VMの設定変更をしたい場合、すでに作成済みのVMに対して設定変更だけ行ってくれるので、勝手に新しいものが作られたりはしません。
スクリプトを実行する
以下のコマンドを叩くだけで、Compute Engineに対してスクリプトの内容に従ってVMが新規に作成されます。また、すでに同名のものが作成済みの場合には、強制停止した上で設定変更を行います(自動再起動はされないので手動で起動が必要です)。
1 |
terraform apply |
実行するか?という問い合わせが途中入るので、「yes」と入力してEnterすれば作業が開始されます。結構早く構築されて起動までします。
図:terraformの実行中の様子
差分の確認
スクリプトのVMの構成内容を変更して、変更差分を確認するコマンドが用意されています。ただし、内容が盛り沢山なので、その中から見つけるのはちょっと大変。
1 |
terraform plan |
図:更新差分を確認できる
削除する
作成したVMはそのまま放置してると恐ろしい金額が請求される可能性があります。40台マックスで立てた場合は、月間で300万円くらい行くと思います。停止しておけばお金が掛からないというものでもなく、ディスクの使用量は継続して請求が掛かることになります。
よって、検証などで立てた場合には作業の終わりと共に必ず、仮想環境を削除しましょう。その為のコマンドが用意されています。但し本番環境もコマンド一発で吹き飛ばすことになるので、要注意です。といっても、必ず確認でyes⇒Enterをしないと実行はされないので、おかしな事をしなければここで踏みとどまれます。
※VMを消しても取得したスナップショットは消えていないので要注意。
1 |
terraform destroy |
図:Destroyで環境を削除します
関連リンク
- Terraform Module for GCP API
- terraformとはなんなのか?
- gcloud CLI のインストールから基本的な使い方-GCP
- Google Cloud Compute EngineをTerraformで構築してみる
- Terraform で入門する Google Cloud【セットアップ編】
- Terraform インストールして GCP 向け設定と GCE でインスタンス構築
- 【初心者】Terraform importを使ってみる
- Terraform リソースの再作成の強制
- Terraform で GCE インスタンスを作成する際に initialize_params を避けるべき理由
- 【Mac】隠しファイルを表示・管理する方法
- Compute Engineを徹底解説!(基本編)
- Terraform on Google Cloud
- Terraform - Get Started - Google Cloud
- Terraform × GCP 入門
- terraform refreshは実体に沿ってstateを更新する
- Terraform provider for Google Cloud
- google_compute_instance
- [terraform] VariableとLocal Valueの使い所
- Terraformのoutputとは何か
- Terraform で変数を使う
- Terraformのインストールと基本操作
- terraform importを使ってTerrafom管理化する
- Terraform - import
- Google Cloud:コンソールで作成したリソースをTerraform importで取り込む
- ディスクのアーカイブ スナップショットと標準スナップショットを作成する
- Terraform連載 第4回:for_eachの使い方