0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform勉強-第31回:SQSをトリガーにしてLambda関数を実行し、CloudWatchでログを確認する

Posted at

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を動的に取得する

./provider.tf
# 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.tf
#---------------------------
# 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.tf
#---------------------------
# 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"

lambda.tf
#---------------------------
# 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.tf
# 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.tf
# 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として定義

./src/lambda_function.py
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のメッセージなどの情報
  • context:
    • Lambda関数の実行に関する情報が含まれており、メモリの使用量や実行時間など、関数実行時に使える情報が入る
  • for record in event['Records']::
    • eventの中にあるRecordsというキーのリストにアクセスし、そのリスト内の各要素を順にrecordとして処理する
    • Lambdaは、複数のレコード(SQSメッセージやSNS通知など)を一度に受け取ることがあり、それらをRecordsというキーに格納する
  • イベントを処理:
    • event['Records']リストに含まれる各レコードのメッセージ本文(record['body'])を出力する
  • 結果の返却:
    • 関数が正常に終了すると、statusCodeとして200bodyとして「Hello from Lambda!」というメッセージが含まれたレスポンスがJSON形式で返される

4. Lambda関数の設定 (aws_lambda_function)

Lambda関数を作成し、SQSキューからのメッセージをトリガーとして処理を実行し、CloudWatch Logsに結果を記録する。

lambda.tf
#---------------------------
# 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モジュールのパス
  • 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キューのトリガー

lambda.tf
# 標準キューのトリガー
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を指定
  • batch_size
    • 一度に読み込むメッセージ数 => 10件ずつSQSからメッセージを読み込んで処理する
  • enabled
    • トリガーを有効にする設定

CloudWatch Logsの設定 (aws_cloudwatch_log_group)

Lambda関数が出力するログをCloudWatch Logsに記録するためのロググループの作成。

lambda.tf
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という名前でロググループを作成される
  • 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関数でエラーが発生している場合の確認に使用できる

今回はここまでにしたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?