githubリポジトリ:"https://github.com/shu130/terraform-study31.git"
SQSキューとLambda関数を連携させ、メッセージの処理やログの管理を行う仕組みをTerraformで構築する
.
├── provider.tf
├── sqs.tf
├── lambda.tf
├── sqs_message_batch_send.sh
├── src
│ └── lambda_function.py
├── terraform.tfvars
└── variables.tf
1. provider.tf
ファイル
今回はprovider.tf
のなかでAWSアカウントIDを動的に取得する
# terraformとawsプロバイダのバージョン
terraform {
required_version = ">= 1.6.2, < 2.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.4.0"
}
}
}
provider "aws" {
profile = var.profile
region = var.region
default_tags {
tags = {
"ManagedBy" = "Terraform"
"Project" = "tf-study31"
}
}
}
# アカウントIDを動的に取得
data "aws_caller_identity" "current" {}
-
data "aws_caller_identity"
: AWSアカウントIDやユーザーIDなどを動的に取得 - アカウントIDの場合は、
${data.aws_caller_identity.current.account_id}
と書くことでどこでも使える
2. sqs.tf
ファイル
3つのSQSキュー(標準キュー、FIFOキュー、デッドレターキュー)を設定する。
1. 標準SQSキュー(aws_sqs_queue "standard"
)
#---------------------------
# SQS
#---------------------------
# 標準SQSキュー
resource "aws_sqs_queue" "standard" {
name = "test-queue-v2"
delay_seconds = 0
max_message_size = 262144
message_retention_seconds = 345600
visibility_timeout_seconds = 30
receive_wait_time_seconds = 0
sqs_managed_sse_enabled = true
kms_data_key_reuse_period_seconds = 300
fifo_queue = false
# ポリシー設定
policy = jsonencode({
Version = "2012-10-17",
Statement = [{
Effect = "Allow",
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
},
Action = "SQS:*",
Resource = "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:test-queue-v2"
}]
})
# デッドレターキュー設定
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.dlq.arn,
maxReceiveCount = 2
})
}
-
delay_seconds
: メッセージが送信されてから利用可能になるまでの遅延時間 -
max_message_size
: メッセージの最大サイズ(バイト単位)=>256KB -
message_retention_seconds
: メッセージ保持時間(秒単位)=>4日間(345600秒) -
visibility_timeout_seconds
: メッセージが他の受信者に見えなくなる期間 =>30秒に設定 -
sqs_managed_sse_enabled
: SQSの暗号化を有効 -
policy
: アクセス許可ポリシーでLambda関数がこのキューにアクセスできるよう、アカウントIDを含むARNを指定 -
redrive_policy
: メッセージが正常に処理されなかったときにDLQ
に送るための設定- deadLetterTargetArn: DLQのキューARNを指定
- maxReceiveCount: 最大2回までメッセージを再試行し、それでも失敗したらDLQに送信
2. FIFO SQSキュー(aws_sqs_queue "fifo"
)
順序保証が必要なメッセージ処理に使われるFIFOキュー。
FIFOキューに固有の属性: fifo_queue
, content_based_deduplication
, fifo_throughput_limit
, deduplication_scope
はFIFOキューに特有の設定。
#---------------------------
# SQS
#--------------------------
# FIFO SQSキュー
resource "aws_sqs_queue" "fifo" {
name = "test-queue.fifo"
fifo_queue = true
content_based_deduplication = true
fifo_throughput_limit = "perQueue"
deduplication_scope = "queue"
}
-
fifo_queue
: FIFOキューを有効にする -
content_based_deduplication
: メッセージの重複排除を有効にする -
fifo_throughput_limit
: FIFOキューのスループット制限 => キュー単位で制限 -
deduplication_scope
: 重複排除のスコープ => キュー全体
3. デッドレターキュー(aws_sqs_queue "dlq"
)
失敗したメッセージが格納される専用キュー。
標準のキューとFIFOキューで処理に失敗したメッセージがこのキューに送信される。
resource "aws_sqs_queue" "dlq" {
name = "test-DLQ-v2"
}
- 標準SQSキューの設定と同じ
-
name: デッドレターキューの名前を
"test-DLQ-v2"
に設定
3. lambda.tf
ファイル
IAMロール/ポリシー、Lambda関数を設定する。
1. IAMロール(aws_iam_role "lambda_role"
)
#---------------------------
# IAM
#---------------------------
# Lambda実行用IAMロール
resource "aws_iam_role" "lambda_role" {
name = "lambda_sqs_role"
assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
Service = "lambda.amazonaws.com"
},
Action = "sts:AssumeRole"
}
]
})
}
- IAMロール: Lambdaに対してAWSリソース(SQS,CloudWatch)にアクセスする権限を持たせる
-
assume_role_policy
: Lambdaがこのロールを使用できるようにするためのポリシー
2. IAMポリシーのアタッチ(aws_iam_role_policy_attachment
)
SQS用途:
# Lambda IAMポリシーのアタッチ
resource "aws_iam_role_policy_attachment" "lambda_sqs_policy" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole"
}
-
aws_iam_role_policy_attachment
: IAMロールに特定のIAMポリシーをアタッチ -
role
: ここではLambda実行用IAMロールを指定 -
policy_arn
: アタッチするポリシーのARNを指定-
AWSLambdaSQSQueueExecutionRole
: Lambda関数がSQSキューをトリガーとして使用、SQSキューからメッセージを読み取り、Lambdaが処理を実行
-
CloudWatch用途:
# Lambda関数のCloudWatchログポリシーのアタッチ
resource "aws_iam_role_policy_attachment" "lambda_cloudwatch_policy" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
}
-
CloudWatchLogsFullAccess
: CloudWatch Logsに対するフルアクセス権限をLambdaに与え、CloudWatch Logsにログを記録したり、ログの確認が可能にする
(権限が大きすぎるが、今回はこのマネージドポリシーを使用)
3. Lambdaで実行するPythonコード (lambda_function.py
)
Lambda関数のエントリーポイントとなる関数名をlambda_handler
として定義
import json
def lambda_handler(event, context):
for record in event['Records']:
print(f"Message Body: {record['body']}")
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
-
event
:- Lambda関数をトリガーする際に送られてくるデータで、リクエストの内容が含まれる
例えば、S3のファイルアップロードやSQSのメッセージなどの情報
- Lambda関数をトリガーする際に送られてくるデータで、リクエストの内容が含まれる
-
context
:- Lambda関数の実行に関する情報が含まれており、メモリの使用量や実行時間など、関数実行時に使える情報が入る
-
for record in event['Records']:
:-
event
の中にあるRecords
というキーのリストにアクセスし、そのリスト内の各要素を順にrecord
として処理する - Lambdaは、複数のレコード(SQSメッセージやSNS通知など)を一度に受け取ることがあり、それらを
Records
というキーに格納する
-
-
イベントを処理:
-
event['Records']
リストに含まれる各レコードのメッセージ本文(record['body']
)を出力する
-
-
結果の返却:
- 関数が正常に終了すると、
statusCode
として200
、body
として「Hello from Lambda!」というメッセージが含まれたレスポンスがJSON形式で返される
- 関数が正常に終了すると、
4. Lambda関数の設定 (aws_lambda_function
)
Lambda関数を作成し、SQSキューからのメッセージをトリガーとして処理を実行し、CloudWatch Logsに結果を記録する。
#---------------------------
# Lambda
#---------------------------
# 関数の作成
resource "aws_lambda_function" "sqs_lambda" {
filename = "${path.module}/src/lambda_function.zip"
function_name = "sqs_lambda_handler"
role = aws_iam_role.lambda_role.arn
handler = "lambda_function.lambda_handler" #=># pythonコードの[ファイル名].[関数名]
runtime = "python3.11"
source_code_hash = filebase64sha256("${path.module}/src/lambda_function.zip")
environment {
variables = {
LOG_LEVEL = "INFO"
}
}
# CloudWatchロググループ
depends_on = [aws_cloudwatch_log_group.lambda_log]
}
-
resource "aws_lambda_function" "sqs_lambda"
:- Lambda関数のリソース定義
-
filename
:- Lambda関数として実行するPythonコードのzipファイルパスを指定(
lambda_function.zip
) -
${path.module}
は、現在のTerraformモジュールのパス
- Lambda関数として実行するPythonコードのzipファイルパスを指定(
-
function_name
:- Lambda関数の名前 =>「sqs_lambda_handler」という名前で定義
-
role
:- ここで前述のIAMロールのARNを指定
-
handler
:
Lambda関数のエントリーポイントを指定:- ここでは、
lambda_function.py
ファイルにあるlambda_handler
関数をエントリーポイントとして実行 -
lambda_function.lambda_handler
の形式で指定することで、Pythonコード内の指定関数が実行される
- ここでは、
-
runtime
:- Lambda関数の実行環境を指定 => Python 3.11 を指定
-
source_code_hash
:- Lambdaコードの変更を検出するためのハッシュ値で、コードが変更されるとハッシュが変わり、Lambda関数が再デプロイされる
-
environment
:- Lambda関数の実行時に使用する環境変数を定義
-
LOG_LEVEL
という環境変数を定義し、ログの出力レベルを制御
-
depends_on
:- 依存関係を指定する属性:
aws_cloudwatch_log_group.lambda_log
が作成されるまでLambda関数の作成を待機し、実行時にCloudWatchログが確実に存在するようにする
- 依存関係を指定する属性:
5. SQSキューのトリガー設定 (aws_lambda_event_source_mapping
)
Lambda関数がSQSのメッセージを受け取るトリガーとして動作するための設定。
標準キューとFIFOキューの両方をトリガーとして設定する。
標準キュー/FIFOキューのトリガー
# 標準キューのトリガー
resource "aws_lambda_event_source_mapping" "standard_sqs_trigger" {
event_source_arn = aws_sqs_queue.standard.arn
function_name = aws_lambda_function.sqs_lambda.arn
batch_size = 10
enabled = true
}
# FIFOキューのトリガー
resource "aws_lambda_event_source_mapping" "fifo_sqs_trigger" {
event_source_arn = aws_sqs_queue.fifo.arn
function_name = aws_lambda_function.sqs_lambda.arn
batch_size = 10
enabled = true
}
-
event_source_arn
:- Lambda関数のトリガーとなるSQSキューのARNを指定 => 標準キュー
-
function_name
:- トリガーを設定するLambda関数を指定:
aws_lambda_function.sqs_lambda.arn
でLambda関数のARNを指定
- トリガーを設定するLambda関数を指定:
-
batch_size
:- 一度に読み込むメッセージ数 => 10件ずつSQSからメッセージを読み込んで処理する
-
enabled
:- トリガーを有効にする設定
CloudWatch Logsの設定 (aws_cloudwatch_log_group
)
Lambda関数が出力するログをCloudWatch Logsに記録するためのロググループの作成。
resource "aws_cloudwatch_log_group" "lambda_log" {
name = "/aws/lambda/sqs_lambda_handler"
retention_in_days = 7
}
-
name
:- Lambda関数に関連するログは
/aws/lambda/{関数名}
の形式で保存される - 今回は
/aws/lambda/sqs_lambda_handler
という名前でロググループを作成される
- Lambda関数に関連するログは
-
retention_in_days
:- CloudWatch Logsで保存する期間を指定 => 7日間の保持期間を指定(7日後に古いログが自動で削除される)
4. terraform apply
後の確認
-
terraform state list
:
現在Terraformの状態に登録されているリソース一覧を表示
リソースが想定通りに作成されているか確認
$ terraform state list
data.aws_caller_identity.current
aws_cloudwatch_log_group.lambda_log
aws_iam_role.lambda_role
aws_iam_role_policy_attachment.lambda_cloudwatch_policy
aws_iam_role_policy_attachment.lambda_sqs_policy
aws_lambda_event_source_mapping.fifo_sqs_trigger
aws_lambda_event_source_mapping.standard_sqs_trigger
aws_lambda_function.sqs_lambda
aws_sqs_queue.dlq
aws_sqs_queue.fifo
aws_sqs_queue.standard
-
terraform show
:
apply
で作成されたリソースの詳細情報を表示
リソースの属性値(ARNなど)を確認するのに便利
$ terraform show | grep url
url = "https://sqs.us-east-1.amazonaws.com/xxxxxxxxxxxx/test-DLQ-v2"
url = "https://sqs.us-east-1.amazonaws.com/xxxxxxxxxxxx/test-queue-v2.fifo"
url = "https://sqs.us-east-1.amazonaws.com/xxxxxxxxxxxx/test-queue-v2"
$ terraform show | grep log_group
# aws_cloudwatch_log_group.lambda_log:
resource "aws_cloudwatch_log_group" "lambda_log" {
log_group_class = "STANDARD"
log_group = "/aws/lambda/sqs_lambda_handler"
5. 動作確認
最新のログをフォロー(リアルタイムモニタリング)
VScodeのターミナルで、
aws logs tail
コマンドで、Lambda関数が連続してトリガーされリアルタイムでログを待ち受けて確認する。
aws logs tail "/aws/lambda/sqs_lambda_handler" --follow
-
--follow
オプションで、新しいログが生成されるとリアルタイムで出力され続ける
SQSトリガーによるLambdaのログを逐次確認したいときに便利
SQSキューにメッセージを送信してLambdaがトリガーされるか確認
キューにメッセージを送信し、Lambda関数がトリガーされてCloudWatchログにメッセージが記録されるか確認
標準キュー用コマンド:
aws sqs send-message-batch \
--queue-url "キューURL" \
--entries "$(seq 10 | jq -nR '[inputs | {Id: (.|tostring), MessageBody: ("standard:" + .)}]')"
FIFOキュー用コマンド:
aws sqs send-message-batch \
--queue-url "キューURL" \
--entries "$(seq 10 | jq -nR '[inputs | {Id: (.|tostring), MessageBody: ("fifo:" + .), MessageGroupId: "aaa"}]')"
CloudWatchでLambda関数のログを確認するAWS CLIコマンド
1. ロググループのリスト表示
Lambda関数に関連するCloudWatchロググループが存在するか確認する。
aws logs describe-log-groups --log-group-name-prefix "/aws/lambda/sqs_lambda_handler"
- =>
/aws/lambda/
で始まるロググループの一覧が表示される (sqs_lambda_handler
)
2. ログストリームのリスト表示
Lambda関数の各実行ごとに異なるログストリームが作成される。
最新のログストリームを確認する。
aws logs describe-log-streams --log-group-name "/aws/lambda/sqs_lambda_handler" --order-by "LastEventTime" --descending
- => 直近のログストリームIDを取得
3. 最新のログイベントを取得
取得したログストリームIDを使いLambda関数の最新の実行ログを表示する。
aws logs get-log-events --log-group-name "/aws/lambda/sqs_lambda_handler" --log-stream-name "<LogStreamName>" --limit 10
-
--limit 10
で表示するログの数を指定する
エラーメッセージのみを検索
エラーの確認には、以下のコマンドで「ERROR」などのキーワードを含むログイベントのみを検索できる。
aws logs filter-log-events --log-group-name "/aws/lambda/sqs_lambda_handler" --filter-pattern "ERROR"
-
--filter-pattern
で「ERROR」を含むログだけを出力できる
Lambda関数でエラーが発生している場合の確認に使用できる
今回はここまでにしたいと思います。