🍩

TerraformでAWS/Lambdaを動かす🪐

2023/05/16に公開

前置き

Terraformを使ってLambda関数を動かしてみました。
Lambdaはよく使うのでTerraformで操作できれば楽になれるはず。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function#example-usage

なにがいいの?

他のAWSサービスと同じ様にterraformでlambdaを管理出来るようになる。

コード群

ディレクトリ構成

.
├── lambda_function
│   └── main.py
└── main.tf

tfファイル

main.tf
data "archive_file" "example_zip" {
  type        = "zip"
  source_dir  = "${path.module}/lambda_function"
  output_path = "${path.module}/example_lambda.zip"
}

resource "aws_lambda_function" "example_lambda" {
  function_name    = "example-lambda"
  handler          = "main.handler"
  runtime          = "python3.10"
  filename         = data.archive_file.example_zip.output_path
  source_code_hash = filebase64sha256(data.archive_file.example_zip.output_path)
  role = aws_iam_role.lambda_role.arn
}

resource "aws_iam_role" "lambda_role" {
  name = "example-lambda-role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_policy" "lambda_policy" {
  name        = "example-lambda-policy"
  description = "IAM policy for the example Lambda function"

  policy = jsonencode({
    Version   = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = [
          aws_cloudwatch_log_group.example_log_group.arn,
          "${aws_cloudwatch_log_group.example_log_group.arn}:*"
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
  role       = aws_iam_role.lambda_role.name
  policy_arn = aws_iam_policy.lambda_policy.arn
}

resource "aws_cloudwatch_log_group" "example_log_group" {
  name = "/aws/lambda/${aws_lambda_function.example_lambda.function_name}"
  retention_in_days = 30
}

実行するコード(python)

main.py
import json

def handler(event, context):
    response = {
        'statusCode': 200,
        'body': 'Hello, Lambda!'
    }
    return response

実行

# デプロイ
$ terraform apply --auto-approve

# Lambda関数実行
$ aws lambda invoke --function-name example-lambda output.txt

# 問題ないことを確認する
$ cat output.txt 
{"statusCode": 200, "body": "Hello, Lambda!"}

更新

filebase64sha256のおかげでファイルの変更をterraformが検知できます。

# ファイル変更
$ vi lambda_function/main.py

# デプロイ
$ terraform apply --auto-approve
... 略 ...
  # aws_lambda_function.example_lambda will be updated in-place
  ~ resource "aws_lambda_function" "example_lambda" {
      ~ source_code_hash               = "4dufGRWFuSd8mdhGfENBdYXNsczizagQckSa1E1za8A=" -> "LI0dGXeKQ5c8N6wDnfL0oh8KZo6Kast3mYsQ3mtAh08="

ポイント

archive_file

ファイルやディレクトリからzipファイルを作成できます。
Lambdaをアップロードする際にzipにする必要があります。

source_code_hash

アップデートのトリガーに使用されるハッシュ。
これが無いとコードを修正した際にterraformが検知できない。

ログ周り

コンソールからLambda関数を作成するとロググループが自動作成されますが、
terraformでまとめて管理する場合は記載します。

resource "aws_cloudwatch_log_group" "example_log_group" {
  name = "/aws/lambda/${aws_lambda_function.example_lambda.function_name}"
  retention_in_days = 30
}

/aws/lambda/<function name>が通常らしいですね。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/monitoring-cloudwatchlogs.html

参考にする箇所

ドキュメントにサンプルがあります。こちらを参考にすればスムーズに進みそうです。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function#example-usage

参考

https://dev.classmethod.jp/articles/terraform-lambda-deployment/

Discussion