📝

TerraformでLambda関数とECRリポジトリを同時に作成したい

に公開

はじめに

TerraformでImageタイプのLambda関数を作成したい時困りますよね。ECRリポジトリを先に作ってイメージをPushしておかないとエラーで作れなくなってしまいます。

│ Error: creating Lambda Function (test-function): operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: hogehoge, InvalidParameterValueException: Source image fugafuga:latest does not exist. Provide a valid source image.
│ 
│   with module.lambda.aws_lambda_function.this[0],
│   on .terraform/modules/lambda/main.tf line 24, in resource "aws_lambda_function" "this":
│   24: resource "aws_lambda_function" "this" {

そこで今日ご紹介するのがDocker Providerです。
これを使うと、

  1. 最新のnginxイメージをPullしてくる
  2. PullしたイメージにECR用のタグをつける
  3. ECRにイメージをPush
    ということが一回のterraform applyで出来るので、同時にlambda関数も作成出来ます。

サンプルコード

########################################################
# Data Import
########################################################
data "aws_caller_identity" "current" {}

########################################################
# Lambda
########################################################
module "lambda" {
  source = "terraform-aws-modules/lambda/aws"

  function_name = "test-function"

  create_package = false

  image_uri    = "${aws_ecr_repository.lambda.repository_url}:latest"
  package_type = "Image"

  depends_on = [aws_ecr_repository.lambda]
}

########################################################
# ECR
########################################################
resource "aws_ecr_repository" "lambda" {
  name = "test-function-repo"

  encryption_configuration {
    encryption_type = "AES256"
  }

  image_scanning_configuration {
    scan_on_push = true
  }

  image_tag_mutability = "IMMUTABLE"
}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_tag" "nginx" {
  source_image = docker_image.nginx.name
  target_image = "${aws_ecr_repository.lambda.repository_url}:latest"
}

resource "docker_registry_image" "nginx" {
  name          = docker_tag.nginx.target_image
  keep_remotely = true
}

data "aws_ecr_authorization_token" "token" {
}

provider "docker" {
  registry_auth {
    address  = "${data.aws_caller_identity.current.account_id}.dkr.ecr.ap-northeast-1.amazonaws.com"
    username = data.aws_ecr_authorization_token.token.user_name
    password = data.aws_ecr_authorization_token.token.password
  }
}

解説

DataImport

操作対象のAWSアカウントIDを特定するために使います。(${data.aws_caller_identity.current.account_id}の部分)

Lambda関数

package_type = "Image"を指定します。(パブリックモジュールを使ってますが普通にresourceで指定してもおk)

ECR

ここがミソ
aws_ecr_repositoryは普通に指定。
docker_imageを定義するとDockerイメージをPullすることが出来ます。今回はnginxの最新版を指定。
docker_tagでPullしてきたイメージにタグ付けすることが出来ます。docker tagコマンドと同じ。
そしてdocker_registry_image.nameに事後のタグ名(ECRにプッシュするタグ名)を指定することでECRにPushを行えます。
ECRの認証はaws_ecr_authorization_tokenやprovider "docker"で指定したregistry_authを使って一時認証情報を使用して行われるようです。

Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

これでECRの作成とLambda関数の作成を一撃で行うことが出来ました。

後処理

なお作成し終わったらもうDocker Providerのリソースは不要なので、余計な定義は消してしまいましょう。
以下をtfファイルから削除してterraform applyコマンドを実行すれば完了です。

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_tag" "nginx" {
  source_image = docker_image.nginx.name
  target_image = "${aws_ecr_repository.lambda.repository_url}:latest"
}

resource "docker_registry_image" "nginx" {
  name          = docker_tag.nginx.target_image
  keep_remotely = true
}

なおECR認証周りは上記定義の削除後に削除してください。同時に削除したいところですがこいつがないとエラーになります。

### 以下はresource3点セット削除後に削除する(terraform applyは不要)
data "aws_ecr_authorization_token" "token" {
}

provider "docker" {
  registry_auth {
    address  = "${data.aws_caller_identity.current.account_id}.dkr.ecr.ap-northeast-1.amazonaws.com"
    username = data.aws_ecr_authorization_token.token.user_name
    password = data.aws_ecr_authorization_token.token.password
  }
}

参考にしたサイト

lambda関数のコンテナイメージサポートをterraformで構築する
https://thaim.hatenablog.jp/entry/2021/07/05/081325

【Terraform】Docker Providerを利用してローカルでインフラ環境を構築してみる
https://www.hanachiru-blog.com/entry/2024/05/30/120000

Discussion