SnowflakeのリソースをTerraformで作成するパイプラインを作る
はじめに
こんにちわ
前回の記事では、公式が出しているチュートリアルをもとにローカル環境からTerraformを利用してSnowflakeのリソースを作成していきました。
今回の記事では、AWSのCodepipelineを用いてデプロイまでをパイプライン化していきます。
作成していくパイプラインは、以下の通りの流れになります。
- Codecommitにて管理されているコードに対して変更を行いCommitを実施するとパイプラインが起動
- Codecommitのアーティファクトを用いて1つ目のCodebuildがビルドを開始し、Terraform initとPlanを実行
- 1つめのBuildが完了後、Amazon SNSにてビルドが完了した旨のメールを発出
- 手動承認の完了をトリガとして、2つ目のCodebuildが起動し、Planの内容をもとにApplyを実行
各サービスは以下の用途で利用します。
Codecommit:コード管理
Codebuild:リソースのビルド&デプロイ
Codepipeline:上記のリソースをパイプラインとして定義
Parameter Store:Codebuildにて利用する情報を管理
EventBridge:コードの変更を検知
環境構築
さて環境構築・・・を始める前に2点。
1点目ですが、今回作成するリソースは前回利用したmain.tfファイルを流用し、追記する形で対応しています。本記事を前回の記事から続きでハンズオン的にやってくださっている方がもしいらっしゃれば、先に前回記事で作成したリソースを対象のSnowflake環境から削除しておいてください。
2点目は、今回の記事では大きく流れを紹介する形になるので各サービスの細かい設定については記載せず、少しわかりにくい部分のみ記載する形にしています。そこは悪しからずということで。
Codecommit
ということで実際に構築していきます。
まずはTFファイルなどを格納しておくリポジトリを作成します。
リポジトリが出来たら前回作成したTFファイルをアップロードしておきます。
Codebuild
Codebuildでは前述したとおり、Init~PlanまでとApply用の2つのビルドプロジェクトを作成します。
ビルドプロジェクトの細かい設定までは記載しませんが、ビルドに利用するコンテナイメージはECRのPublic GalleryにあるTerraformのイメージを利用します。
また各ビルドプロジェクトで利用するbuildspecは以下の通りです。
version: 0.2
env:
parameter-store:
SNOWFLAKE_PRIVATE_KEY: /snowflake-tf/private-key
SNOWFLAKE_ACCOUNT: /snowflake-tf/account
variables:
SNOWFLAKE_USER: TF-USER
SNOWFLAKE_AUTHENTICATOR: JWT
# 後続ステップであるAmazon SNSで通知する際、ビルドプロジェクトのURLを載せたいためBUILD_URLとして環境変数を設定しています
exported-variables:
- BUILD_URL
phases:
pre_build:
on-failure: ABORT
commands:
- echo "Start PRE-BUILD Phase."
- "terraform init -input=false"
build:
commands:
- "terraform plan -input=false -out=./.tfplan"
# post_buildフェーズにて当該ビルドURLをEXPORTしています
post_build:
commands:
- "export BUILD_URL=`echo $CODEBUILD_BUILD_URL`"
artifacts:
base-directory: ${CODEBUILD_SRC_DIR}
files:
- "**/*"
version: 0.2
env:
parameter-store:
SNOWFLAKE_PRIVATE_KEY: /snowflake-tf/private-key
SNOWFLAKE_ACCOUNT: /snowflake-tf/account
variables:
SNOWFLAKE_USER: TF-USER
SNOWFLAKE_AUTHENTICATOR: JWT
phases:
build:
commands:
- echo "Start Apply Phase."
- "terraform show ./.tfplan"
- "terraform apply -input=false ./.tfplan"
念のためbuildspecの作りについて補記しておきます。
-
まず前回の記事でローカル環境から実行する際、Terraformから叩かれるURLは、ACCOUNT_REGIONの値を入れた「account_locator.cloud_region_id」の形式をとっていましたが、こちらは現在レガシーとなっています。
そのためREGIONの記載はせず、「SNOWFLAKE_ACCOUNT」の環境変数に「orgname-account_name」の値を入れ込んでおきます。そうすることで現在推奨されている形式のURLでアクセスできるようになります。
-
通常、terraform init ~ plan ~ applyまでは一定の間隔で実施するため特に意識せずでよいと思いますが、今回はinit ~ planまでのビルドプロジェクトとapplyのビルドプロジェクトは異なるものを利用します。
そのためplan時の内容をtfplanとして保存しておいて、それを用いてapplyを実行する形にしています。
また各terraformコマンドは出力に対して応答する所謂対話形式となりますが、今回はビルドプロジェクト内で実行する必要があるため、各terraformコマンドでは引数で -input=falseを入れ込むことで対話なしの形に対応しています。
Amazon SNS
トピックとサブスクリプションを作成します。
今回はメールで承認依頼を投げたいので、SNSのサブスクリプションには受信可能なEmailアドレスを登録しておきます。
AWS Codepipeline
これまでに作成したリソースを各ステージに設定します。
- Sourceステージ:作成したCodecommitリポジトリを設定
- Buildステージ:Codebuild1つ目を設定
- Approvalステージ:Manual Approvalの設定。先ほど作成したSNSのトピックを設定
- Deployステージ:Codebuild2つ目を設定
基本的には上記の通り設定していけばよいですが、1点だけ手動承認のメールを送る際にレビュー用URLを載せたいので、Codebuildの方で設定した環境変数を利用するために以下の設定をしておきます。
- Buildステージの「変数の名前空間」を設定(今回はわかりやすくBuildVariablesと設定)
- Approvalステージの「レビュー用URL」欄に「#{[Buildステージの名前空間].[buildspecで設定したBuildURLの環境変数]}」と設定
実際に動かしてみる
構築は完了したので、tfファイルに追加で構築するリソースを追記してパイプラインがちゃんと稼働するか確認していきます。
今回はDB(TESTDB-PIPELINE)を追加で作成します。
# これから実行されるTerraformについてはSnowflakeと依存関係がある旨の記載
terraform {
required_providers {
snowflake = {
source = "Snowflake-Labs/snowflake"
version = "~> 0.87"
}
}
}
# provider情報を記載
provider "snowflake" {
role = "SYSADMIN"
}
# TF_DEMOという名前のDBを作成
resource "snowflake_database" "db" {
name = "TF_DEMO"
}
# TESTDB-PIPELINEという名前のDBを作成
resource "snowflake_database" "testdb" {
name = "TESTDB-PIPELINE"
}
# TF_DEMOという名前でXSサイズのWarehouseを作成
resource "snowflake_warehouse" "warehouse" {
name = "TF_DEMO"
warehouse_size = "xsmall"
auto_suspend = 60
}
順調に進んで、
無事にSNSに承認用URLも掲載されていそうです。
手動承認も実施し、デプロイフェーズも完了しました。
ということでSnowsight上でリソースがちゃんと作成されているか確認しに行きましょう。
無事にできていそうですね!
まとめ
といった感じでCodepipelineにうまく乗せてデプロイができました。
今回はあくまで個人開発を想定して作成していましたが、正式なPJとしてやっていく場合にはチーム開発となることが想定されます。
そのため競合が発生する可能性を考慮し、DynamoDBやStateファイルを利用したステート管理というのが必要になってきます。
この辺の実装は余裕があれば記事を書こうかなと。
ということで今回の目標は達成したのでこの辺で。
それでは。
Discussion