Lambdaファンクション
AWS Lambdaの最も重要なコンセプトと言えます。利用できるプログラミング言語は執筆時点ではNode.jsのみですが、将来的には他の言語のサポートも予定されています。コードはマネージメントコンソールの画面上に用意されている組み込みのエディタを利用して書くことも可能ですし、ローカルPCなどで書いたコードをZip形式にしてアップロードすることも可能です。なお、ネイティブライブラリを含む各種ライブラリを利用することも可能であり、その場合は利用するライブラリをコードと一緒にZipファイルとしてまとめた上でアップロードする必要があります。
Lambdaファンクションではコードだけでなく、その実行環境に関する指定も行います。メモリ容量はデフォルトでは128MBとなっていますが、64MBごとに最大1GBまで設定が可能となっています。また、メモリ容量の変更に応じて利用可能なCPU能力なども連動して変動します。
Lambdaファンクションの実行をどのくらいの時間でタイムアウトさせるかの設定も必要です。こちらはデフォルトでは3秒となっていますが1秒単位で最大60秒まで指定することが可能です。タイムアウト時間が最大で60秒というのを聞くと少なく感じる方も多いかと思われますが、AWS Lambdaは比較的シンプルで小規模な処理をイベント発生ごとに実行するイベントドリブンアーキテクチャのためのプラットフォームであり、既存のバッチジョブを代替するプラットフォームではないということです。
その他に設定する項目として、ファンクションの起動と実行に関わる権限をIAMロールというものを利用して設定する必要があります。こちらに関しては後半でもう少し細かく説明します。
これらの設定とあわせてLambdaファンクションとイベントの発生元となるAWSリソース(特定のAmazon S3バケット、Amazon DynamoDB StreamもしくはAmazon Kinesis Stream)を紐付ける必要があります。このAWSリソースのことをAWS Lambdaでは「イベントソース」と呼びます。リソースに変更があると、AWS Lambdaはそのリソースに紐付けられたLambdaファンクションを実行します。その際、イベントの発生量に応じてそれらを適切に処理すべく必要に応じてコンピュートリソース(Amazon EC2インスタンス)を起動し管理します。しかし、このことをユーザが気にする必要はありません。AWS Lambdaはユーザに代わってこのあたりのリソース管理を適切かつ自動的に行い、必要なくなればそれらのシャットダウンも行います。
なお、AWS LambdaはマネージメントコンソールだけでなくAWS SDKとAWS Command Line Interface(CLI)からも操作することが可能です。
プログラミングモデル
Lambdaファンクションは、作成時に指定したNode.jsの関数として実行され、そこから処理が開始されます。関数内部では関数呼び出しの際にパラメータとして渡されるイベントのデータにアクセスすることが可能です。イベントのデータはJSON形式となっており、Lambdaファンクションが起動されるきっかけとなったイベントに関する詳細な情報を含みます。例えばAmazon S3のイベントであればPUTされたバケットの名前やARN(Amazon Resource Name、AWSリソースを一意に識別するためのID)や実際にPUTされたオブジェクトのキーなどが含まれます。以下はAmazon S3のPUTイベント発生時に送られてくる情報のサンプルです(一部抜粋)。
{ "Records": [ { "eventVersion": "2.0", "eventSource": "aws:s3", "awsRegion": "us-east-1", "eventTime": "1970-01-01T00:00:00.000Z", "eventName": "ObjectCreated:Put", "userIdentity": { "principalId": "AIDAJDPLRKLG7UEXAMPLE" }, --- 省略 --- "s3": { "s3SchemaVersion": "1.0", "configurationId": "testConfigRule", "bucket": { "name": "sourcebucket", "ownerIdentity": { "principalId": "A3NL1KOZZKExample" }, "arn": "arn:aws:s3:::mybucket" }, "object": { "key": "HappyFace.jpg", "size": 1024, "eTag": "d41d8cd98f00b204e9800998ecf8427e" } } } ] }
なお、このイベントのデータはサービスごとに異なります。また、カスタムイベントを発行する際はJSON形式であれば任意のデータを渡すことが可能です。
Lambdaファンクションとして開発するアプリケーションの実装上の注意点として、ステートレスに実装する必要があることが挙げられます。というのもLambdaファンクションは内部的にはコンテナとして実行されており、起動の都度生成され(一部例外はあるものの)終了時には破棄されます。したがって、Lambdaファンクション自身ではデータを永続化することができません。データの永続化が必要な場合は、AWSのサービスであればAmazon DynamoDBであったりAmazon S3であったり、その他であってもインターネット経由でアクセス可能なストレージを利用する必要があります。
最後に、用意するコードそのものはNode.jsおよびLinuxの環境下で本来備わっている機能を利用することが可能です。プロセスをspawnしたりスレッドを生成することも可能ですし、実行ファイルの実行も可能です。ただし、ディスクIOに関しては/tmp領域のみ読み書き可能となっており容量も512MBまでと制限されています。また前述の通り、ファンクションの実行終了時にはコンテナが破棄されてしまうので/tmp領域の内容もファンクションの終了時には消えてしまいます。なお、AWS SDK for JavaScript in Node.jsとImageMagickはあらかじめ導入済みなので、すぐに利用することができます。
イベントソース
前述のとおり、イベントの発生元となるAWSリソースのことをAWS Lambdaではイベントソースと呼びますが、イベントソースの違いによってファンクション起動時の挙動が異なります。
Pushモデル
Amazon S3やカスタムイベントは、イベント発生に応じて直接Lambdaファンクションを起動します。これをPushモデルと呼んでおり、Amazon S3とカスタムイベントがこれにあたります。このモデルの特徴としてはイベントの実行が順不同となることです。またリトライの仕方にも違いあり、3回までのリトライとなっています。
Pullモデル
一方でAWS Lambdaに対して直接的にイベント発行を行わないようなサービスもあり、その場合はAWS Lambdaがそれらへポーリングを行い自らイベントを取得します。これはPullモデルと呼ばれており、その特性はPushモデルと大きく異なります。Amazon DynamoDBとAmazon Kinesisをイベントソースとする場合はこのモデルとなり、イベントソースとして登録したストリームに対してAWS Lambdaが自動的にイベントを取得しに行きます。
また、Pushモデルとの大きな違いとして順序性があることが挙げられます。つまりストリームに入ってきた順にイベントが処理されるということです。リトライに関しても大きな違いがあります。Pullモデルではリトライは無限に行われます。つまりイベントソースとなるストリームにあるデータが期限切れになるまでリトライを繰り返すということです。
最後に非常に重要な制限としてLambdaファンクションとそれに紐付けるイベントソースは同一のリージョンである必要があります。例えばAmazon S3の場合、US EASTのLambdaファンクションのイベントソースとして指定可能なAmazon S3のバケットはUS EASTに存在するバケットになります。
Invocation RoleとExecution Role
Lambdaファンクションを語る上で忘れずに触れる必要があるのが、先ほどのPushモデ ル/Pullモデルそれぞれの図にも記載のあるInvocation RoleとExecution Roleです。Invocation Roleは誰がファンクションを実行できるかを決定し、Execution Roleはファンクションができること(どのAWSのリソースにどういったアクションを行えるか)を決定づけます。実際の細かい権限はそれぞれIAMロールとして用意し、割り当てることで実現しています。細やかな権限管理を可能にするため、それぞれ別個のIAMロールを割り当てることが可能となっています。
なお、IAMロールとはAWS Identity and Access Management(以下、IAM)というサービスで用いられる概念です。簡単に言うと、AWSサービスに対してリクエストを行う権限を役割として定義するものであり、特定のユーザーまたはグループに関連付けられものではありません。Invocation Role、Execution Roleともにイベントソースのタイプ(PushもしくはPull)によって必要となる権限やポリシーの設定方法が異なります。
Invocation Role
Pushモデルの場合、必要となるのはイベントソースがLambdaファンクションを起動できる権限です。一方でPullモデルの場合はAWS LambdaがストリームからイベントをPullできる権限が必要となります。Pushモデルの場合、2つのポリシーをIAMロールに与える必要があります。まずはAccecc-policyと呼ばれるもので、以下の例ではAmazon S3に対してlambda:InvokeAsyncを許可します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": "*", "Action": [ "lambda:InvokeAsync" ] } ] }
次にTrust-policyです。こちらは誰がそのロールを引き受けられるかを指定します。以下の例ではAmazon S3にsts:AssumeRoleの許可を与えています。条件として特定のバケットから発信される場合のみAmazon S3がイベント発行するよう制限しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "s3.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals":{ "sts:ExternalId": "arn:aws:s3:::bucket name" } } } ] }
一方、Pullモデルの場合でも2つのポリシーが必要になります。以下の例ではAccess policyとしてAmazon Kinesisのストリームに対する読み取りとlambda:InvokeAsyncというアクションに対して許可を行っています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Resource": "*", "Action": [ "kinesis:ReadStream"] } ] }
また、Trust policyとして誰がそのロールを引き受けられるのか明らかにする必要があります。以下の例ではsts:AssumeRoleというアクションをAWS Lambdaにのみ許可しています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Execution Role
Execution Roleは必要なAWSリソースへのアクセスを許可するIAMロールのことです。Lambdaファンクションは実行の際、ここで指定されたIAMロールにそってAWSのリソースへのアクセスが許可されます。作成したそれぞれのIAMロールには2つのポリシーがアタッチされています。
まず、Access policyとしてファンクションが必要とするAWSリソースへのアクセスを許可します。AWS LambdaはAmazon CloudWatch Logsにログを書き込みますので以下の例のようなポリシーを必要とします。この例ではAmazon CloudWatch Logsの全てのログアクション(logs:*)を許可しています。
{ "Statement": [ { "Action": [ "logs:*" ], "Effect": "Allow", "Resource": "arn:aws:logs:*:*:*" } ] }
自身で用意したLambdaファンクションに応じて必要となるその他のパーミッションを追加します。もし、ファンクションがAmazon S3へとオブジェクトを保存するものであれば、このポリシー内で関連するアクションを許可する必要があります。Amazon S3のアクションに関してはAmazon S3のDeveloper Guideを参照してください。
次に、Trust policyですが、ここでは誰がそのロールを引き受けるのかを明示します。以下のポリシーではAWS Lambdaが引き受けられるように許可しています。1つ大事なこととして、IAMロールを作成しているユーザがAWS Lambdaに対してこのロールを引き受けるための権限を渡しています。従ってユーザはこれを許可するためにiam:PassRoleというアクションに対して許可されている必要があります。もし管理者がこのロールを作成しているならば、そのユーザはiam:PassRoleを含む全ての権限を持っています。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
一見複雑で難しいと思われる方も多いかと思いますが、AWS Lambdaのコンソール上ではこの辺りの定義は簡単なものであれば自動で生成されますし、ポリシーのジェネレータも存在していますので考え方に慣れてしまえばそう複雑なものではありません。IAMロールに関するより詳細な情報に関しては、こちらのドキュメントを参照ください。
モニタリング
AWS Lambdaは各Lambdaファンクションの実行を監視しており、リクエスト数、遅延、可用性とエラー率のメトリクスをAmazon CloudWatch内に保存します。メトリクスはAWS Lambdaコンソール上のダッシュボードでもグラフとして見ることができます。 実行時のログはAmazon CloudWatch Logsに保存され、後から参照が可能となっています。ログには実行開始/終了に加え、メモリ使用量や実行時間といったファンクション実行時に実際に消費したリソースに関する内容が出力されます。また、任意のメッセージをログとして出力することも可能です。