概要
こんにちは、キュービックでSREをやっているYuhta28です。キュービック内のテック技術について発信します。
以前弊社でのTerraformの取り組みについて紹介しました。
この中で環境によってリソース数の差分が生じる、例えば本番環境なら冗長化のためNAT Gatewayを3台稼働させるが、検証環境ならコスト最適化のため1台のみ稼働させると言ったケースではfor_each
を使って動的にリソース数を管理する方法について紹介しました。
ではAWS CodePipelineで本番環境のみにApprovalステージを追加したいというような要望のときはどうすればよろしいでしょうか🤔
CodePipelineのステージはパラメーターの一つで複数行に渡り記述されるのでfor_each
で分岐するとなるとうまくいきません。
# CodePipeline作成Terraform(一部パラメーター省略) resource "aws_codepipeline" "example-pipeline" { artifact_store { location = var.s3-location type = "S3" } name = "pipeline-name" # ソースステージ stage { name = "Source" action { category = "Source" configuration = { Branch = "main" Owner = "master" PollForSourceChanges = "false" Repo = "pipeline-repo" } name = "Source" namespace = "SourceVariables" output_artifacts = ["SourceArtifact"] owner = "ThirdParty" provider = "GitHub" region = "ap-northeast-1" run_order = "1" version = "1" } } # ビルドステージ stage { name = "Build" action { category = "Build" configuration = { ProjectName = "build-project" } input_artifacts = ["SourceArtifact"] name = "Build" output_artifacts = ["BuildArtifact"] owner = "AWS" provider = "CodeBuild" region = "ap-northeast-1" run_order = "1" version = "1" } } # 承認ステージ(本番環境のみ作成) stage { name = "Confirm" action { category = "Approval" name = "RequestApprove" owner = "AWS" provider = "Manual" region = "ap-northeast-1" run_order = "1" version = "1" } } # デプロイステージ stage { name = "Deploy" action { category = "Deploy" input_artifacts = ["BuildArtifact"] name = "Deploy" owner = "AWS" provider = "ECS" region = "ap-northeast-1" run_order = "1" version = "1" } } }
承認ステージ部分が本番環境だけに必要なステージです。ここだけを環境ごとに分割したいという状況は一般的にあると思います。
この問題を解決してくれるのがdynamic
ブロックとよばれるものです。今回このdynamic
ブロックを用いて環境毎に異なるリソースパラメータの動的作成について紹介します。
dynamicブロックについて
dynamic
はブロック単位のループ処理を実装したいときに使います。
例えばセキュリティグループの作成でdynamic
ブロックを使ったとします。
# セキュリティグループ作成 locals { ingress_web = [ # [description, from_port, to_port, protocol, cidr_blocks] ["HTTPS from VPC", 443, 443, "tcp", "10.0.0.0/8"], ["HTTP from VPC", 80, 80, "tcp", "192.168.0.0/16"], ] } resource "aws_security_group" "web" { name = "allow-web" vpc_id = aws_vpc.main.id dynamic "ingress" { for_each = local.ingress_web content { description = ingress.value[0] from_port = ingress.value[1] to_port = ingress.value[2] protocol = ingress.value[3] cidr_blocks = ingress.value[4] } } egress = [ { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } ] tags = { Name = "allow-web" } }
ここではingressルールでHTTP通信とHTTPS通信の許可設定を付与する箇所でdynamic
ブロックを使っています。ingressのパラメータはポートが異なっても設定項目は同じなので設定値をingress_web
という変数でまとめればingressの記述回数が一回で済みます。
これを応用してdynamicでループするかどうかをTrue or Falseで分岐するようにすれば本番環境のみに承認ステージを追加することができます。
dynamicブロックによる分岐設定
先程のTerraformファイルを以下のように修正します。
# CodePipeline作成Terraform(一部パラメーター省略) resource "aws_codepipeline" "example-pipeline" { artifact_store { location = var.s3-location type = "S3" } name = "pipeline-name" # ソースステージ stage { name = "Source" action { category = "Source" configuration = { Branch = "main" Owner = "master" PollForSourceChanges = "false" Repo = "pipeline-repo" } name = "Source" namespace = "SourceVariables" output_artifacts = ["SourceArtifact"] owner = "ThirdParty" provider = "GitHub" region = "ap-northeast-1" run_order = "1" version = "1" } } # ビルドステージ stage { name = "Build" action { category = "Build" configuration = { ProjectName = "build-project" } input_artifacts = ["SourceArtifact"] name = "Build" output_artifacts = ["BuildArtifact"] owner = "AWS" provider = "CodeBuild" region = "ap-northeast-1" run_order = "1" version = "1" } } # dyanmicを追加、論理型変数でTrue時のみリソースを作成する dynamic "stage" { for_each = var.production_approval ? [1] : [] content { name = "Confirm" action { category = "Approval" name = "RequestApprove" owner = "AWS" provider = "Manual" region = "ap-northeast-1" run_order = "1" version = "1" } } } # デプロイステージ stage { name = "Deploy" action { category = "Deploy" input_artifacts = ["BuildArtifact"] name = "Deploy" owner = "AWS" provider = "ECS" region = "ap-northeast-1" run_order = "1" version = "1" } } }
dynamic
ブロックを追加し、production_approval
という変数がTrueの時リソースを一回作成するように設定します。
production_approval
はTrue/Falseの論理型変数なので、variables.tf
には以下のように記載します。
# variables.tf variable "production_approval" { type = bool default = false description = "本番環境のみにApprovalステージを設定するためのif分岐" }
本番環境のterraform apply
実行先のCodePipelineモジュールファイルにtrueを加えます。
module "cba-codepipeline" { source = "../../modules/codepipeline ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # trueとすることでfor_eachで承認ステージを作成する production_approval = true }
これによって本番環境では承認ステージ付きのCodePipelineが作成され、検証環境では承認ステージなしのCodePipelineを作成できます。
(注:production_approval
のデフォルト値をfalseにしているので検証環境に変数をセット不要です)
所感
dynamic
ブロックを使ってCodePipelineの承認ステージの作成可否を環境ごとに分岐できるようにしました。
Moduleで汎用化する際、パラメータ単位でリソースを作り分けたいというケースもあると思います。そうしたケースではdynamic
ブロックを使って環境別の条件別分岐を実装すると良いと思います。
みなさんもぜひ試してみてください。
参考文献
関連記事
Terraformに関連する記事はこちらもご覧ください。