■ はじめに
https://dk521123.hatenablog.com/entry/2024/05/30/010920
の続き。 今回は、前回の AWS Lambda の Hello worldを元に 色々と拡張してみる
目次
【1】Lambdaレイアーを付与 0)使用するAPI 1)フォルダ構成 2)サンプル 【2】S3バケットのイベントトリガー 0)使用するAPI 1)フォルダ構成 2)サンプル 【3】Lambda に AWS roleを付与 1)フォルダ構成 2)サンプル
【1】Lambdaレイアーを付与
0)使用するAPI
aws_lambda_layer_version
* Lambda レイヤー を作成
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_layer_version
1)フォルダ構成
├── outputs │ ├── layer/ │ ├── venv/ │ └── zipfile/ ├── lambda │ ├── requirements.txt │ └── main.py └── terraform └── main.tf
2)サンプル
* main.py は、以下の関連記事を参照のこと
Lambda ~ Python / 外部モジュール追加 ~
https://dk521123.hatenablog.com/entry/2024/05/25/005456
main.tf
#=============================== # locals #=============================== locals { lambda_layer_name = "demo-lambda-layer" lambda_function_name = "demo-lambda" # Need to modify, otherwise error 'AccessDeniedException: Cross-account pass role is not allowed' iam_arn = "arn:aws:iam::123456789012:role/your-role" } #=============================== # Layer #=============================== # Step1: Lambdaレイアーの実ファイル作成準備 resource "null_resource" "prepare_to_make_demo_layer_file" { triggers = { "requirements_diff" = filebase64("${path.module}/../lambda/requirements.txt") } provisioner "local-exec" { command = <<-EOF rm -rf ${path.module}/../outputs/layer/ && pip install -r ${path.module}/../lambda/requirements.txt -t ${path.module}/../outputs/layer/python EOF on_failure = fail } } # Step2: Lambdaレイアーの実ファイル作成 data "archive_file" "make_demo_layer_file" { depends_on = [ null_resource.prepare_to_make_demo_layer_file, ] type = "zip" source_dir = "../outputs/layer" output_path = "../outputs/zipfile/demo_layer.zip" } # Step3: Lambdaレイアー作成 resource "aws_lambda_layer_version" "demo_layer" { layer_name = local.lambda_layer_name filename = data.archive_file.example_layer.output_path source_code_hash = data.archive_file.example_layer.output_base64sha256 compatible_runtimes = ["python3.12"] } #=============================== # Lambda #=============================== # Step1: Lambda関数のファイルをZIP圧縮 data "archive_file" "demo_zip" { type = "zip" source_dir = "../scripts" output_path = "../outputs/zipfile/demo_lambda.zip" } # Step2: cloudwatchのロググループ resource "aws_cloudwatch_log_group" "demo_log_group" { name = "/aws/lambda/${aws_lambda_function.demo_lambda.function_name}" retention_in_days = 30 } # Step3: Lambda関数作成 resource "aws_lambda_function" "demo_lambda" { function_name = local.lambda_function_name filename = data.archive_file.demo_zip.output_path role = local.iam_arn handler = "main.handler" source_code_hash = data.archive_file.example_function.output_base64sha256 runtime = "python3.12" memory_size = 128 timeout = 60 # ★ここで指定している★ layers = [aws_lambda_layer_version.demo_layer.arn] }
requirements.txt
requests==2.28.0
参考文献
https://qiita.com/neruneruo/items/feca4ea15e2230c188b4
【2】S3バケットのイベントトリガー
0)使用するAPI
aws_lambda_permission
* S3 などの外部ソースが Lambda 関数を呼び出す
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission
1)フォルダ構成
├── lambda │ └── main.py └── main.tf
2)サンプル
* main.py は、以下の関連記事を参照のこと
Lambda ~ Python / S3トリガー ~
https://dk521123.hatenablog.com/entry/2024/05/23/162229
main.tf
# Lambdaをアップロードする際にzipにする必要があるので # ファイルをZIP圧縮する data "archive_file" "demo_zip" { type = "zip" source_dir = "${path.module}/lambda" output_path = "${path.module}/demo_lambda.zip" } # Lambda関数の作成 resource "aws_lambda_function" "demo_lambda" { function_name = "demo-lambda" handler = "main.handler" runtime = "python3.12" filename = data.archive_file.demo_zip.output_path source_code_hash = filebase64sha256(data.archive_file.demo_zip.output_path) # ★Need to modify, otherwise error 'AccessDeniedException: Cross-account pass role is not allowed' role = "arn:aws:iam::123456789012:role/your-role" environment { variables = { TARGET_URL = "${var.bucket_name}", DRY_RUN = "true" } } } resource "aws_cloudwatch_log_group" "demo_log_group" { name = "/aws/lambda/${aws_lambda_function.demo_lambda.function_name}" retention_in_days = 30 } data "aws_s3_bucket" "target_s3_bucket" { bucket = "bucket.test.com" } resource "aws_lambda_permission" "demo_allow_s3_bucket" { statement_id = "AllowExecutionFromS3Bucket" action = "lambda:InvokeFunction" function_name = "${aws_lambda_function.demo_lambda.arn}" principal = "s3.amazonaws.com" source_arn = "${data.aws_s3_bucket.target_s3_bucket.arn}" } resource "aws_s3_bucket_notification" "demo_bucket_notification" { bucket = "${data.aws_s3_bucket.target_s3_bucket.id}" lambda_function { lambda_function_arn = "${aws_lambda_function.demo_lambda.arn}" events = ["s3:ObjectCreated:*"] filter_prefix = "images/" filter_suffix = ".png" } depends_on = [ aws_lambda_permission.demo_allow_s3_bucket ] }
参考文献
https://hands-on.cloud/s3-trigger-lambda-terraform-example/
【3】Lambda に AWS roleを付与
1)フォルダ構成
├── lambda │ └── main.py ├── local.tf ├── cloudwatch.tf ├── iam.tf └── lambda.tf
2)サンプル
local.tf
locals { lambda_function_name = "demo-lambda" s3_bucket_name = "your-s3-bucket" }
cloudwatch.tf
resource "aws_cloudwatch_log_group" "demo_log_group" { name = "/aws/lambda/${local.lambda_function_name}" retention_in_days = 30 }
iam.tf
resource "aws_iam_role" "demo_lambda_role" { name = "demo-lambda-role" assume_role_policy = jsonencode({ "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "lambda.amazonaws.com" }, "Effect": "Allow", "Sid": "ForLambda" } ] }) } # For S3 write/read access # See also https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_s3_rw-bucket.html resource "aws_iam_policy" "demo_lambda_policy" { name = "demo-lambda-policy" description = "IAM policy for the Lambda function" policy = jsonencode({ Version = "2012-10-17" Statement = [ { "Sid": "ListObjectsInBucket", "Action": [ "s3:ListBucket" ], "Effect": "Allow", "Resource": ["arn:aws:s3:::${local.s3_bucket_name}"] }, { "Sid": "AllObjectActions", "Action": [ "s3:*Object" ], "Effect": "Allow", "Resource": ["arn:aws:s3:::${local.s3_bucket_name}/*"] }, { Effect = "Allow" Action = [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ] Resource = [ aws_cloudwatch_log_group.demo_log_group.arn, "${aws_cloudwatch_log_group.demo_log_group.arn}:*" ] } ] }) } resource "aws_cloudwatch_log_group" "example_log_group" { name = "/aws/lambda/${aws_lambda_function.example_lambda.function_name}" retention_in_days = 30 }
lambda.tf
# Lambdaをアップロードする際にzipにする必要があるので # ファイルをZIP圧縮する data "archive_file" "demo_zip" { type = "zip" source_dir = "${path.module}/lambda" output_path = "${path.module}/demo_lambda.zip" } # Lambda関数の作成 resource "aws_lambda_function" "demo_lambda" { function_name = "demo-lambda" handler = "main.handler" runtime = "python3.12" filename = data.archive_file.demo_zip.output_path source_code_hash = filebase64sha256(data.archive_file.demo_zip.output_path) role = aws_iam_role.demo_lambda_role.arn }
main.py
import json def handler(event, context): response = { 'statusCode': 200, 'body': 'Hello, World!' } return response
参考文献
https://zenn.dev/not75743/articles/7a7d3a2fc7e788
関連記事
Terraform ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/04/05/000224
Terraform ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/12/09/222057
Terraform ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2023/05/03/000000
Terraform ~ local / variable ~
https://dk521123.hatenablog.com/entry/2023/12/24/173633
Terraform ~ tfstate / Backend ~
https://dk521123.hatenablog.com/entry/2023/05/05/004939
Terraform ~ Terraformあれこれ ~
https://dk521123.hatenablog.com/entry/2023/05/15/205352
Terraform ~ AWS Lambda / 入門編 ~
https://dk521123.hatenablog.com/entry/2024/05/30/010920
Terraform ~ AWS ECR ~
https://dk521123.hatenablog.com/entry/2023/05/23/002314
Terraform ~ 複数環境へデプロイすることを考える ~
https://dk521123.hatenablog.com/entry/2023/05/06/003645
Lambda ~ Python / 入門編 ~
https://dk521123.hatenablog.com/entry/2021/10/07/103317
Lambda ~ Python / 外部モジュール追加 ~
https://dk521123.hatenablog.com/entry/2024/05/25/005456
Lambda ~ Python / S3トリガー ~
https://dk521123.hatenablog.com/entry/2024/05/23/162229