🦍
Terraformでファイルの差分を検知する
はじめに
最近ちょろっとTerraformでLambdaを構築しました。
その際にコードが変更されたら差分検知してデプロイしたくて試行錯誤したので、備忘録としてそのやり方を残します。
サンプルのリポジトリを用意しているので、全体像を知りたい方はこちらも参照してください。
環境
Treraformは1.9.0を使っています。
また、ステート管理はs3にバケットを用意したのと、同時applyできないようにdynamodbを使っています。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.54.1"
}
random = {
source = "hashicorp/random"
version = "~> 3.6.2"
}
}
required_version = ">= 1.8.5"
backend "s3" {
profile = "techlead"
region = "ap-northeast-1"
bucket = "xxxx"
dynamodb_table = "xxxx"
key = "terraform.tfstate"
encrypt = true
}
}
差分検知について
サンプルリポジトリの構成をもとに説明します。
$ tree -L 1
.
├── LICENSE
├── README.md
├── compose.yaml
├── lambda
└── terraform
今回はLambdaのコードがあるディレクトリ配下のファイル一覧をfileset()
で取得してさらにregexall()
を使って拡張子がgo
、sum
、mod
のファイルのみを絞りこみます。
terraform/lambda.tf
locals {
binary_path = "build/bootstrap"
archive_path = "build/handler.zip"
}
locals {
target_files = [
for file in fileset("../lambda", "**") : file if length(regexall(".*\\.(go|sum|mod)$", file)) != 0
]
}
これらのファイルのハッシュ値を結合して、terraform変数長の上限を回避するためさらにハッシュ値を取得します。
これで対象のファイルに変更があれば、ハッシュ値が変わります。
terraform/lambda.tf
locals {
concatenated_hashes = sha256(join("", [for file in local.target_files : filesha256(join("", ["../lambda/", file]))]))
}
terraform_data.triggers_replace
を使って、算出したハッシュ値concatenated_hashes
が変わったら、terraform_data
リソースを再評価させています。
これによりバイナリが変わり、depends_on
で依存を指定してるarchive_file
とaws_lambda_function
も再評価され、ステートが更新されデプロイされます。
terraform/lambda.tf
resource "terraform_data" "function_binary" {
triggers_replace = [
local.concatenated_hashes,
]
provisioner "local-exec" {
working_dir = "../lambda"
environment = {
GOOS = "linux"
GOARCH = "amd64"
CGO_ENABLED = "0"
GOFLAGS = "-trimpath"
}
command = "go build -mod=readonly -ldflags='-s -w' -o ${local.binary_path} ."
}
}
data "archive_file" "example" {
depends_on = [
terraform_data.function_binary
]
type = "zip"
source_file = "../lambda/${local.binary_path}"
output_path = "../lambda/${local.archive_path}"
}
resource "aws_lambda_function" "example" {
depends_on = [
terraform_data.function_binary
]
filename = "../lambda/${local.archive_path}"
function_name = "example"
role = aws_iam_role.lambda_execution.arn
handler = "handler"
runtime = "provided.al2"
source_code_hash = data.archive_file.example.output_base64sha256
timeout = "900"
}
まとめ
正直このやり方では、ファイル数が多くなるとハッシュ値計算時間が伸びるので、あんまり行けていないなと感じています。
調べてもあんまり情報がなかったのでひとまずこれでやっていくんですが、もしこうした方がよいよって方がいたら是非コメントください。
Discussion