✨
AWS Lambda + Terraform最小構成 2024/6
いつも忘れるのでメモ。
基本構成
- ソースコードはECRにpushする(言語の差異を吸収するため)
- タグは
latest
を利用する(プログラムの変更に伴うリソースの変更が起きないようにするため) - main.tfのみ
main.tf
変更が必要な部分はmyをprefixに付けています。
variable使ってもよかったけど、結局リソース名にvariable使えないので置き換えて利用してください。
- my_lambda_role
- my_lambda_function
- my-app
# プロバイダ
provider "aws" {
region = "ap-northeast-1"
}
# 実行ロール
# lambda.amazonaws.comに対してAssumeRoleを許可する
resource "aws_iam_role" "my_lambda_role" {
name = "my_lambda_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
description = "IAM Role for the lambda function"
}
# CloudWatch ログへの書き込みアクセス許可
# https://docs.aws.amazon.com/ja_jp/aws-managed-policy/latest/reference/AWSLambdaBasicExecutionRole.html
resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" {
role = aws_iam_role.my_lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# Lambda関数
resource "aws_lambda_function" "my_lambda_function" {
function_name = "my_lambda_function"
memory_size = 128
timeout = 30
role = aws_iam_role.my_lambda_role.arn
package_type = "Image"
image_uri = "your-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/my-app:latest"
}
# ECRリポジトリ
resource "aws_ecr_repository" "lambda_repo" {
name = "my-app"
}
デプロイ
# リソースの作成
terraform init
terraform apply -auto-approve
# ECRへのpush
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin account-id.dkr.ecr.us-west-2.amazonaws.com
docker build -t my-app .
docker tag my-app:latest account-id.dkr.ecr.us-west-2.amazonaws.com/my-app:latest
docker push account-id.dkr.ecr.us-west-2.amazonaws.com/my-app:latest
カスタマイズ
構造ログ
# Lambda関数
resource "aws_lambda_function" "my_lambda_function" {
...
logging_config {
log_format = "JSON"
}
}
プライベートサブネットに配置する
RDSのようなプライベートサブネットに配置したサービスにアクセスする時に利用するため、作成のところは実際には使わないはず。
# VPC
resource "aws_vpc" "my_vpc" {
cidr_block = "10.0.0.0/16"
}
# サブネット
resource "aws_subnet" "my_subnet" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
}
# インターネットゲートウェイ
resource "aws_internet_gateway" "my_igw" {
vpc_id = aws_vpc.my_vpc.id
}
# ルートテーブル
resource "aws_route_table" "my_route_table" {
vpc_id = aws_vpc.my_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.my_igw.id
}
}
# ルートテーブルアソシエーション
resource "aws_route_table_association" "my_route_table_association" {
subnet_id = aws_subnet.my_subnet.id
route_table_id = aws_route_table.my_route_table.id
}
# Lambdaセキュリティグループ
resource "aws_security_group" "lambda_sg" {
vpc_id = aws_vpc.my_vpc.id
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Lambda関数
resource "aws_lambda_function" "my_lambda_function" {
...
vpc_config {
subnet_ids = [aws_subnet.my_subnet.id]
security_group_ids = [aws_security_group.lambda_sg.id]
}
}
Secrets Managerからシークレットを取得する
その他Lambdaからアクセスするリソースを追加する場合は、IAMロールにinline_policyを追加する形で対応すればよい。
resource "aws_secretsmanager_secret" "my_secret" {
name = "my_secret"
}
resource "aws_iam_role" "my_lambda_role" {
...
inline_policy {
name = "my_lambda_policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue"
]
Resource = aws_secretsmanager_secret.my_secret.arn
}
]
})
}
}
ソースコードとインフラをまとめて管理する
一番簡易なpackage_type=zipバージョン
terraform apply時にソースコードをzip化してLambdaにアップロードします。
# アーカイブ
data "archive_file" "my_app" {
type = "zip"
source_dir = "lambda.ts"
output_path = "lambda_function.zip"
}
# Lambda関数
resource "aws_lambda_function" "my_lambda_function" {
...
package_type = "Zip" # ← デフォルトなので省略可
filename = data.archive_file.my_app.output_path
source_code_hash = data.archive_file.my_app.output_base64sha256
handler = "index.handler"
runtime = "nodejs20.x"
}
Rustの場合
バイナリビルドになるため、環境の差異に注意する必要があります。
cargo lambda build --release --output-format zip
resource "aws_lambda_function" "my_lambda_function" {
...
filename = "bootstrap.zip"
runtime = "provided.al2023"
}
Discussion