概要
チーム開発を行なっている際、メンバーごとにAWS上で環境を用意したい時ありますよね。
環境なんていくつあっても困りませんからね〜。
今回!Terragrunt + GitHub Actionsでうまく複数メンバー分環境を立てるためのインフラを作成したので、それを説明しようと思います。
ご意見、アドバイスお待ちしています٩( ᐛ )و
環境
$ terragrunt -v
terragrunt version v0.46.2
$ terraform -v
Terraform v1.3.7
手法
技術選定
- Terraform
- Terragrunt
TerragruntはTerraformのラッパーです。
今回、採用した理由としては
-
tfstate
間の依存関係定義が容易 -
backend
ブロック中で環境変数にアクセスができる
の2点となります。
tfstate
間の依存関係定義が容易
環境を分けるとは言ったものの、完全に独立なリソースを作るわけではありません。
VPCやALB等、共通で参照するものもいくつかあります。
新しい環境はこれらの値(idやARN)に依存するわけですが、Terraformでtfstate
間で値を受け渡すには手間がかかります。
具体的にはtfstate1
でoutput
した値をtfstate2
のtfvars
にハードコード or 実行時に明示的に値を受け渡す必要があります。
一方Terragruntはdependency blockを使用することで、tfstate
間で簡単に値を共有することが可能です。
dependency "common" {
config_path = "../common_resources"
}
メンバーの環境のtfstate
はそれぞれ共通の依存関係があるため、この記述がすごくマッチしました。
backend
ブロック中で環境変数にアクセスができる
GitHub ActionsでのTerragrunt実行を想定しているため、tfstate
ファイルはlocalに保存しておくわけにはいきません。
また、ユーザー毎にtfstateを管理するキーも分ける必要があります。
Terraformでは、backendブロック内で直接環境変数を参照することができません。代わりに、-backend-configオプションを使用してterraform initの一部として引数を渡す必要があります。これは、各環境での手動の操作が必要となります。
backend "s3" {
bucket = "dummy-terraform"
key = "staging/terraform.tfstate"
region = "ap-northeast-1"
}
$ terraform init \
-backend-config="bucket=real-terraform"\
-backend-config="key=userA/terraform.tfstate"\
-backend-config="region=us-east-1"
一方で、Terragruntでは、backendブロック内で直接環境変数を参照することが可能です。
remote_state {
backend = "s3"
config = {
bucket = "${get_env("STATE_BUCKET", 'hogehoge-terraform')}"
key = "${get_env("ENVIRONMENT", 'staging')}/terraform.tfstate"
region = "ap-northeast-1"
}
}
$ export STATE_BUCKET=real-terraform
$ export ENVIRONMENT=userA
$ terragrunt init
GitHub Actionsでシークレットから取得した環境変数として設定すれば、Terragruntがそれを読み取ってプロビジョニングしてくれます。
アーキテクチャ
とりあえず完成形です!
/common_resources
VPC, ALB, Route53, ECR等の共通で使用するある種の「箱」のようなリソースを作成します。
/user_resources
(localからでも可能ですが、)GitHub Actions上でworkflow_dispatchをトリガーとしこのリソースがプロビジョニングされます。
実行したGitHub Userの名前をキーとして以下のようなリソースを作成します。
ALBのリスナールールでホストヘッダーを見て、各ユーザー固有のFargateにリクエストを捌くようになっています。
初回デプロイ時は
- Route53にサブドメインの登録(
<your github username>.<your domain>
) - ALBリスナールールを追加
- ECSクラスタ、サービスの作成
が行われ、2回目以降はGitHubActionsでECRにpushされたImageを元にタスク定義を書き換えサービスを更新します。
結論
いかがでしょうか?
ユーザー毎に環境をGitHub Actionsで作成するためのアーキテクチャの一案です。
もっといい方法があるかもしれないですが、今の私ではこれが最適解でした😫
よければ参考にしてみて下さいっ💡
今後
すごい細かいですけど、Fargateは稼働時間でも利用料金が発生するため、ことステージング環境は夜間(業務時間外)は停止させたいですよね。
ECS on EC2であればASGで特定の時間コンテナインスタンスの数を0にすれば実現可能ですが、Fargateの場合どうすればいいのでしょうか・・・?
え…?夜間は業務時間外ではないですって?
す、すいませんでした🙇