kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Terraform で Amazon ECR のライフサイクルポリシーを設定する

Terraform で Amazon ECR リポジトリのライフサイクルポリシーを設定するときに aws_ecr_lifecycle_policy リソースのドキュメントを読むとヒアドキュメントを使った例が載っている📝

個人的にはヒアドキュメントを使いたくなく,他の実装案を考えながら試してみた❗️

1. ヒアドキュメントで直接書く

まずはドキュメントに載っているヒアドキュメントの例を試す.今回はサンプルとして Policy on tagged image のライフサイクルポリシーを使っている.ヒアドキュメントで EOF を書く部分や閉じる EOF のインデントが気になる💨

ちなみに <<-EOF とすればインデントはキレイに書けるようになるけどまだ微妙さは残る...

developer.hashicorp.com

main.tf

resource "aws_ecr_repository" "playground" {
  name = "playground"
}

resource "aws_ecr_lifecycle_policy" "playground" {
  repository = aws_ecr_repository.playground.name

  policy = <<EOF
{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Keep last 30 images",
            "selection": {
                "tagStatus": "tagged",
                "tagPrefixList": ["v"],
                "countType": "imageCountMoreThan",
                "countNumber": 30
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}
EOF
}

2. jsonencode 関数に JSON をそのまま指定する

jsonencode 関数を使えば指定した値を JSON に変換できる.JSON を文字列のまま指定できるため,結果的にヒアドキュメントを jsonencode 関数に置き換えられる.JSON を指定すると区切り文字を : にした Map 型になるため,terraform fmt コマンドで整形できるというメリットもある👌

developer.hashicorp.com

main.tf

resource "aws_ecr_repository" "playground" {
  name = "playground"
}

resource "aws_ecr_lifecycle_policy" "playground" {
  repository = aws_ecr_repository.playground.name

  policy = jsonencode(
    {
      "rules" : [
        {
          "rulePriority" : 1,
          "description" : "Keep last 30 images",
          "selection" : {
            "tagStatus" : "tagged",
            "tagPrefixList" : ["v"],
            "countType" : "imageCountMoreThan",
            "countNumber" : 30
          },
          "action" : {
            "type" : "expire"
          }
        }
      ]
    }
  )
}

3. file 関数で JSON ファイルを読み込む

file 関数を使うと JSON ファイルを直接読み込める.固定の JSON を読み込めれば Terraform コードをシンプルに保てる👌

developer.hashicorp.com

lifecycle.json

{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Keep last 30 images",
            "selection": {
                "tagStatus": "tagged",
                "tagPrefixList": ["v"],
                "countType": "imageCountMoreThan",
                "countNumber": 30
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}

main.tf

resource "aws_ecr_repository" "playground" {
  name = "playground"
}

resource "aws_ecr_lifecycle_policy" "playground" {
  repository = aws_ecr_repository.playground.name

  policy = file("lifecycle.json")
}

4. jsonencode 関数に Map 型を指定する

案2 と似てるけど jsonencode 関数に区切り文字を = にした Map 型を指定する.rulePrioritydescription などキー名に " を書く必要がなく,個人的には JSON をそのまま指定するよりも可読性が高くて良いと思う👌

main.tf

resource "aws_ecr_repository" "playground" {
  name = "playground"
}

resource "aws_ecr_lifecycle_policy" "playground" {
  repository = aws_ecr_repository.playground.name

  policy = jsonencode(
    {
      rules = [
        {
          rulePriority = 1,
          description  = "Keep last 30 images",
          selection = {
            tagStatus     = "tagged",
            tagPrefixList = ["v"],
            countType     = "imageCountMoreThan",
            countNumber   = 30
          },
          action = {
            type = "expire"
          }
        }
      ]
    }
  )
}

5. templatefile 関数と jsonencode 関数を組み合わせてテンプレート化する

templatefile 関数と jsonencode 関数を組み合わせるとテンプレートファイルから JSON を作れる❗️${description}${countNumber} など変数を埋め込めるのは便利〜 \( 'ω')/

例えば「アプリケーションごとに Amazon ECR リポジトリは複数あるけどライフサイクルポリシーはほとんど同じだからできる限り共通化したい」という場面にピッタリ👌

テンプレートファイルの拡張子はドキュメントで推奨されている .tftpl にしてある📝

developer.hashicorp.com

lifecycle.tftpl

${jsonencode(
  {
    rules = [
      {
        rulePriority = 1,
        description  = "${description}",
        selection = {
          tagStatus     = "tagged",
          tagPrefixList = ["v"],
          countType     = "imageCountMoreThan",
          countNumber   = "${countNumber}"
        },
        action = {
          type = "expire"
        }
      }
    ]
  }
)}

main.tf

resource "aws_ecr_repository" "playground" {
  name = "playground"
}

resource "aws_ecr_lifecycle_policy" "playground" {
  repository = aws_ecr_repository.playground.name

  policy = templatefile("lifecycle.tftpl", {
    description = "Keep last 30 images"
    countNumber = 30
  })
}

参考

docs.aws.amazon.com