Chapter 05

Lambda関数のトリガーにはどういったものが存在する?

みふう
みふう
2024.03.26に更新

この章について

この章ではLambda関数のトリガーにはどういったものが存在するのかを具体的に説明していきます

またこの章では実際にS3とLambdaを利用してトリガーに対する理解を深めていきます

振り返り: トリガーとは

「Lambdaとは?」の章でも紹介しましたが、Lambdaにおける「トリガー」とは何でしょうか?

イメージとしては下記ですね^^

  1. 花粉が飛んできた!!
    1. イベント
  2. はっくしょん!!
    1. トリガー

つまり、Lambdaにおけるトリガーとは「Lambdaを実行するきっかけ」です

トリガーの種類

ここでは、トリガーにはどういった種類や利用例があるのかを見ていきます

トリガーの種類は非常に多いため、この章では主にS3の利用例と実際の利用方法の紹介だけにとどめます

Amazon S3(Simple Storage Service)

利用例

下記はS3とLambdaを連携した際の利用ケースの一例ですが、利用ケースは要件によって無数に存在します

  • ユーザーがS3バケットに画像や動画ファイルをアップロードすると、Lambda関数が自動的にトリガーされ、リサイズ、形式変換、品質調整、サムネイル生成などの処理を行う
  • S3にアップロードされたデータやログファイルを定期的にLambda関数で分析し、異常検知、統計情報の生成、インデックス作成などを自動で行う
  • 静的ウェブサイトのコンテンツがS3にアップロードされると、Lambda関数がHTMLファイルやCSSファイルを自動で圧縮、最適化する
    また、ウェブサイトのサイトマップの自動生成や、更新内容をデータベースに記録する処理も実行

何がトリガーになるのか

「S3において、何がLambdaを実行するトリガーとなるのか?」というのはは比較的に単純で、オブジェクトの作成(PUT、POST、COPY)、削除、復元などのS3バケット内の操作がそのままイベントとなり、トリガーになります

トリガーの設定方法

ではでは、実際にS3を利用してトリガーの設定方法を見ていきましょう

S3バケットの作成

まずはS3バケットを作成します

画面右上の「バケットを作成」を選択

  • 下記を設定
    • バケットタイプ
      • 汎用
    • バケット名
      • 任意のbucket名を入力してください
    • オブジェクト所有者
      • ACL無効化(推奨)
    • このbucketのブロックパブリックアクセス設定
      • パブリックアクセスをすべてブロック
    • バケットのバージョニング
      • 無効にする
    • 暗号化タイプ
      • Amazon S3 マネージドキーを使用したサーバー側の暗号化(SSE-S3)
    • バケットキー
      • 有効にする
設定画像のスクショ(参考)



作成完了

次に、作成したS3バケットにtestフォルダを作成します
(ローカルにtestフォルダを作成したらドラッグアンドドロップでアップロードできます👍)

testフォルダを作成する理由は、このtestフォルダ配下のファイルが操作(PUT, DELETE...)をトリガーにLambda関数を実行させるためです

Lambdaの作成

Lambdaの関数作成画面に行き、「関数の作成」ボタンを選択

  • 下記を設定
    • 作成タイプ
      • 一から作成
    • 関数名
      • 任意の関数名を入力してください
    • ランタイム
      • Amazon Linux 2023
    • アーキテクチャ
      • x86_64
    • 実行ロール
      • AWSポリシーテンプレートから新しいロールを作成
    • ロール名
      • 任意のロール名を入力してください
    • ポリシーテンプレートオプション
      • Amazon S3 オブジェクトの読み取り専用アクセス権限
設定画像のスクショ(参考)


ランタイムのAmazon Linux 2023って何?Goが無いぞ?
前提: そもそもランタイムって何?

ランタイムは、プログラムが実行される際に必要な実行環境やサポートシステムを指しています
(言語の実行エンジン、必要なライブラリ...)

一言で言うとプログラムの実行環境であり、ランタイム環境とは「プログラムが生きるための世界」ですね

そのうえで、Goランタイムサポートは廃止された

Go は、他のマネージドランタイムとは異なる方法で実装されています。Go は実行可能バイナリにネイティブにコンパイルされるため、専用の言語ランタイムは必要ありません。Go 関数を Lambda にデプロイするには、OS のみのランタイム (providedランタイムファミリー) を使用します。
Go による Lambda 関数の構築

Lambdaが提供していたGo専用のランタイム環境が「Go 1.x マネージドランタイム」です

そして、そのGo 1.x マネージドランタイムは廃止になりました

ランタイムとカスタムランタイムの違い

マネージドランタイム(ランタイム)は特定のプログラミング言語に最適化され、AWSによって完全に管理される実行環境

一方で、カスタムランタイムは開発者がより柔軟に実行環境を制御できるオプション

これにより、AWSが直接サポートしていない言語で書かれた関数や、特定のシステム設定が必要な関数もLambdaで実行することが可能になる

Amazon Linux 2023はカスタムランタイムの一例であり、開発者が任意の実行可能ファイルをデプロイして実行できるようにするもの

つまり、カスタムランタイムを使用することで、より広範な言語やライブラリのサポート、カスタマイズされた実行環境を利用できるようになる

なぜGoランタイムサポートは廃止されたのか

前提として、プログラミング言語には大きく分けてインタープリタ言語とコンパイル言語が存在する

  • インタープリタ言語
    • プログラムをコンパイルせず、直接実行する
    • プログラムを直接実行するためにはその言語専用のインタープリタが必要なため、Lambdaでインタープリター言語を実行するにはそれぞれの言語用に最適化されたマネージドランタイム環境が必要
  • コンパイル言語
    • ソースコードはコンパイルプロセスを経て実行可能なバイナリファイルに変換される
    • このバイナリファイルは、特定のオペレーティングシステム上で直接実行可能であり、プログラミング言語の実行時環境(ランタイム)に依存しない
    • つまり、コンパイルされたバイナリファイルを実行するためには、基本的にはそのバイナリが対応するオペレーティングシステムがあれば十分

つまり、Go言語のコードはビルドするとバイナリファイル(実行可能バイナリ)が作成されるため、特定のオペレーティングシステム上で実行さえすればGo専用のランタイム環境を用意する必要が無い!!

なのでAWSとしては「今までGo専用のランタイム環境提供してたけど専用じゃなくてもいけるよね?だから廃止にするね!」って感じで廃止にした流れですね

Amazon Linux 2023とは何か

Amazon Linux 2023は、AWSが提供するLinuxベースのオペレーティングシステムの最新バージョンであり、Lambdaでカスタムランタイムとして利用できるものです

なぜAmazon Linux 2023でGoのプログラムを実行できるのか

Go言語(または他のコンパイル言語)からビルドされたバイナリファイルは、その実行に言語のランタイム環境を必要としません
(バイナリファイルを実行する環境さえあればよい)

ビルドプロセスを経て生成されたバイナリファイルは、特定のオペレーティングシステム上で直接実行可能な形式であり、その実行を可能にしてくれるOSがAmazon Linux 2023です

なぜJavaはコンパイル言語なのにランタイム環境があるのか

Javaはコンパイル言語でありながら、特殊な例

Javaのコードはバイトコードにコンパイルされ、このバイトコードを実行するためにはJava Virtual Machine (JVM) が必要

JVMはプラットフォームに依存しない実行環境を提供し、Javaプログラムが異なるオペレーティングシステム上でも一貫して実行できるようにする

このため、Javaは「Write Once, Run Anywhere」(一度書けばどこでも実行できる)という特性を持つ

Javaのランタイム環境(JVM)は、Javaプログラムが実行される際に、バイトコードを特定のシステム上で実行可能な機械語に変換する役割を担っている

このプロセスは「Just-In-Time」(JIT)コンパイレーションと呼ばれ、プログラムの実行速度を向上させることができる

したがって、Javaはコンパイル言語でありながら、その実行にはJVMという特定のランタイム環境が必要になるため、Java専用のランタイム環境が存在している感じですね

https://zenn.dev/ikarin0825/articles/30627c72d43494

ポリシーテンプレートオプションで「Amazon S3 オブジェクトの読み取り専用アクセス権限」を選択すると勝手にAWS側でロールを作ってくれるの?

Lambdaで関数を作成する際にポリシーテンプレートを使用して特定の権限(例として「Amazon S3 オブジェクトの読み取り専用アクセス権限」)を選択すると、AWSはその権限を持つ実行ロール(IAMロール)を自動的に作成してくれる

これにより、Lambda関数は指定されたポリシーに基づいた権限を持つことになり、例えば、選択したポリシーテンプレートがS3の読み取り専用アクセス権限を持つ場合、そのLambda関数はS3バケット内のオブジェクトを読み取ることができるようになる

作成が完了したら、画面左側の「triggerを追加」を選択

  • 下記を設定
    • バケット名
      • 先ほど作成したバケット名を入力
    • Event types
      • PUT
      • ※PUTをイベントとして扱う
    • Prefix - オプション
      • /test
      • ※testフォルダに対するPUTをイベントとして扱う
    • Suffix - オプション
    • .txt
    • ※testフォルダに対する.txtファイルのPUTをイベントとして扱う(なるほどね)

トリガーを追加できました

ではでは、Lambdaに実行コードをアップロードしましょう

まずはアップロードする基となるコードを作成します

コードの作成手順

ここではGo言語を利用してLambdaで実行する関数を実装しますが、他の言語でも流れに変わりはなく、下記の順序で進みます

  1. プロジェクト作成
    1. 例: sampleフォルダ
  2. プロジェクト配下に言語特有のファイルを作成(Goなら~.go)
    1. ファイルをビルド
  3. ビルドファイルをZIP化
    1. ZIPファイルをLambdaへアップロード

まずはsampleフォルダを作成し、下記のコマンドを実行します

go mod init sample

go.modファイルが作成されたら、main.goを作成して下記のコードをコピペします(コードはお好みでOK)

package main

import (
	"fmt"

	"github.com/aws/aws-lambda-go/lambda"
)

func hello() {
	fmt.Println("Hello World")
}

func main() {
	lambda.Start(hello)
}

次に、main.goをビルドします

※Lambdaの実行環境はLinuxのため、Linux用の実行可能ファイルをビルドする必要があります

bash
GOOS=linux GOARCH=amd64 go build -o bootstrap main.go

powershell
$Env:GOOS="linux"; $Env:GOARCH="amd64"; go build -o bootstrap main.go

sampleディレクトリ配下にbootstrapという実行可能バイナリができたため、これをZIP化します

bash
zip lambda-function.zip bootstrap

powershell
Compress-Archive -Path bootstrap -DestinationPath lambda-function.zip

参考
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/golang-handler.html
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-golang.html

ビルドしたバイナリファイルをZIP化したら、画面右側の「アップロード元」を選択し、.zip ファイルを選択

.zipファイルをドラッグアンドドロップして「保存」を選択すればアップロード完了です!!

ではでは、S3バケットのtestフォルダ配下に.txtファイルをアップロードしてみましょう

正しく動作すれば、textフォルダ配下に.txtファイルをアップロードしたタイミングでLambda関数が起動し"Hello World"が出力されるはずです

S3バケットのtestフォルダに移動し、任意の.txtファイルをアップロードします(名前超適当..)

では実際に実行されているか見に行きやしょう
作成したLambda関数のモニタリングタブを開き「CloudWatch ログを表示」を選択

お、一件ログストリームが追加されているのでリンクをクリック

"Hello World"と出力されてるゥゥゥゥゥゥゥゥゥ!!!!!

S3とLambdaの連携はざっくりこんな感じです

ただ、実務で利用する場合はアクセス権限やバケット名、Lambda関数名などをもっとしっかり考える必要があるので、今までの流れはあくまで参考程度にしてください😊

S3以外のトリガーの種類

Amazon DynamoDB

詳細
利用例
  • データ処理と変換
    • DynamoDBに保存されたデータをLambdaを使用してリアルタイムで処理・変換する
      • 例えば、新しいデータが追加された時にデータの整形や検証を行うなど
  • 非同期処理
    • DynamoDBにデータが追加または更新された際に、バックエンドで非同期に処理を行うためにLambdaを使用する
      • 例えば、ユーザー登録後にウェルカムメールを送信するなど
何がトリガーになるのか

テーブルの変更データ(挿入、更新、削除)がイベントとなり、それがLambda関数のトリガーとなります

トリガーの設定方法
  1. DynamoDBテーブルでDynamoDB Streamsを有効にする
  2. Lambda関数を作成し、トリガーとしてDynamoDB Streamを指定する
  3. Lambda関数には、ストリームからのデータを処理するためのロジックを実装する

Amazon API Gateway

詳細
利用例
  • RESTful APIの構築
    • API Gatewayをフロントエンドに、Lambdaをバックエンドのロジックとして使用して、RESTful APIを構築する
  • データのバリデーションと変換
    • APIリクエストを受け取った時に、そのデータのバリデーションや変換をLambdaで行う
  • サーバレスウェブアプリケーション
    • ウェブアプリケーションのバックエンドとしてLambdaを使用し、API Gatewayを通じてクライアントからのリクエストを処理する
何がトリガーになるのか

API Gatewayのエンドポイントに設定されたHTTPリクエスト(GET、POST、PUT、DELETEなど)がLambda関数のトリガーになる

トリガーの設定方法
  1. API GatewayでAPIを作成し、リソースとメソッド(エンドポイント)を設定する
  2. メソッドの統合タイプとしてLambda関数を選択し、対象のLambda関数を指定する
  3. 必要に応じてリクエストやレスポンスのマッピングテンプレートを設定する

Amazon SQS

詳細
利用例
  • 非同期メッセージ処理
    • SQSを介して、システム間で非同期にメッセージを交換し、Lambdaでそれらのメッセージを処理する
何がトリガーになるのか

SQSキューに新しいメッセージが到着すると、それがイベントとなりLambda関数のトリガーになる

トリガーの設定方法
  1. SQSキューを作成する
  2. Lambda関数のトリガーとして、SQSキューを指定する
  3. Lambda関数で、SQSメッセージを受け取り処理するロジックを実装する

Amazon CloudWatch

詳細
利用例
  • アラート駆動型処理
    • CloudWatchアラートをトリガーにしてLambda関数を実行し、異常検知時の自動応答やリソースの自動調整などを行う
  • ログ処理
    • CloudWatch Logsに記録されたログデータに基づいて、Lambda関数を実行し、ログデータの解析や加工、外部システムへの送信を行う
何がトリガーになるのか

CloudWatch AlarmsやCloudWatch Logsの特定のイベントがLambda関数のトリガーになる

トリガーの設定方法
  1. CloudWatchのアラームまたはロググループを設定する
  2. Lambda関数のトリガーとしてCloudWatchのアラームやロググループを指定する
  3. Lambda関数で、CloudWatchからのイベントに応じた処理を実装する

Amazon EventBridge

詳細
利用例
  • アプリケーション間のイベント通信
    • EventBridgeを使用して、アプリケーション間でイベントをルーティングし、それに応じてLambda関数を実行する
  • タイムリーなデータ処理
    • システム内の特定のイベントを捕捉し、リアルタイムでデータを処理または変換する
何がトリガーになるのか

EventBridgeルールにマッチするイベントがLambda関数のトリガーになる

トリガーの設定方法
  1. EventBridgeでイベントルールを作成し、イベントパターンを定義する
  2. Lambda関数をイベントルールのターゲットとして指定する
  3. Lambda関数で、EventBridgeからのイベントに基づいて処理を実装する

同時に複数のイベントがトリガーされた場合の挙動

Lambdaを使用する際に、同時に複数のイベントがトリガーされた場合の挙動について見ていきましょう

復習として、Lambdaはイベント駆動型のコンピューティングサービスであり、特定のAWSサービス(例:Amazon S3、Amazon DynamoDB)やHTTPリクエスト(API Gateway経由)などからのイベントに応答してコードを自動的に実行します

同時に複数のイベントがトリガーされた場合の挙動は、主に以下のようになります

イベントの処理

Lambda関数は、それぞれのイベントを独立して処理します

つまり、複数のイベントが同時にトリガーされた場合、それぞれのイベントに対してLambda関数のインスタンスが起動し、並列に処理を行います

同時実行制限

Lambdaには「同時実行制限」というものが存在し、これはアカウントごとに設定されています
(この制限値は、アカウントが同時に実行できるLambda関数のインスタンスの最大数を指す)

同時実行制限に達した場合、追加のイベントはキューに入れられ、処理可能になるまで待機します
(Lambdaの同時実行制限や内部キューの詳細は以降の章で詳しく紹介します)

スケーリング

Lambdaは要求に応じて自動的にスケールアップします

つまり、イベントの数が増えるとLambdaはより多くのインスタンスを起動してこれらのイベントを処理します
(ただし、このスケーリングは同時実行制限内で行われます)

つまりLambdaは同時に複数のイベントがトリガーされても対応できるものの、制限を超えるとイベントがキューに格納され、処理が可能になるまで待機する、っていう感じですね👍

まとめ

この章ではLambdaのトリガーの種類や実際にS3と連携してどのようにLambda関数が実行されるのかを見てきました

次章では「Lambdaで実行できる時間は短い?長時間実行したい場合どうする?」という部分を具体的に見ていきます

れっつらごー!

参考サイト一覧

https://qiita.com/Oukaria/items/28bb5675fecb865348a2
https://dev.classmethod.jp/articles/lambda-idempotency/
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-services.html