AWS LambdaはRESTful APIの開発時だけではなく、特定のイベントをトリガーとして処理を行うことができます。今回はServerlessFrameworkを利用し、S3に新しくオブジェクトが追加された際に関数を起動するところまでをまとめます。
準備
Node.jsとServerlessFrameworkがインストールされた状態で設定を行っていきます。
初期ファイルの作成
sls
コマンドを実行しServerlessFrameworkのテンプレを取得、npm init
でpackage.jsonを作成します。
$ sls ? What do you want to make? AWS - Node.js - Starter ? What do you want to call this project? test1 $ cd test1 $ npm init
必要なモジュールのインストール
S3上のオブジェクト(ファイル)を操作する場合はAWS SDKを入れます。
$ npm install aws-sdk
サンプル
オブジェクトが追加されるとconsole.logにバケットとオブジェクト名を出力するサンプルを作成してみます。
serverless.yml
以下のYAMLは次のような意味になります。指定されたバケットが存在しない場合は自動的に作成される点に注意が必要です。
- 「東京リージョン」の
- バケット「s3bucket.example.com」内に、
- 「images/*.jpg」というネーミングルールのオブジェクトが追加された場合
- 「handler.js内のcreate関数」を実行する
service: s3eventtest frameworkVersion: '3' provider: name: aws runtime: nodejs14.x region: ap-northeast-1 # 東京リージョン environment: S3_BUCKET: s3bucket.example.com # バケットを指定 iam: role: statements: # S3の指定バケット上のオブジェクトの入出力を許可 - Effect: Allow Action: - s3:GetObject - s3:PutObject Resource: - arn:aws:s3:::${self:provider.environment.S3_BUCKET}/* # CloudWatchにログ出力を許可 - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: - "*" functions: eventCreat: handler: handler.create events: - s3: bucket: ${self:provider.environment.S3_BUCKET} event: "s3:ObjectCreated:*" rules: - prefix: images/ - suffix: .jpg # すでに存在するバケットを対象とする場合は以下のコメントを外す # existing: true
イベントの種類
ここではevent
にオブジェクトが作成された場合を示すs3:ObjectCreated:*
を指定していますが、他にも様々なイベントが用意されています。
例えば以下のイベントが利用できます。
イベント | 内容 |
---|---|
s3:ObjectCreated:* | オブジェクト作成 |
s3:ObjectRemoved:* | オブジェクト削除 |
s3:ObjectRestore:* | Glacierから復元(開始、完了) |
s3:LifecycleExpiration:* | ライフサイクル設定でオブジェクトを削除 |
s3:ObjectTagging:* | オブジェクトにタグ追加・削除 |
s3:ObjectACL:PUT | オブジェクトのACL設定が変更 |
特定のオブジェクトだけ対象にする
rules
で特定のファイル名のときだけLambdaを起動できるフィルター機能があります。
- prefix
- ファイル名の一部
- suffix
- 拡張子
もちろんLambda内で判定しても良いのですが、起動回数に応じて料金かかっちゃいますからね。
注意点
個人的にハマったのですが、resources
でS3のバケットを作成しなくても上記だけで自動的にバケットが作成されます。逆にresourcesを書くとdeploy中に「すでにバケットが存在している」という旨のエラーが表示され途中で停止します。
Lambdaのコード例
関数の第一引数(event)に新しく作成されたオブジェクトの情報が渡されますので、これをもとに自分のやりたい処理を定義します。
'use strict'; /** * S3に作成されたファイル名を記録する * */ //---------------------------------------------------- // モジュール //---------------------------------------------------- const AWS = require('aws-sdk'); const s3 = new AWS.S3({ apiVersion: '2006-03-01'}); // リージョン情報を更新 AWS.config.update({region: 'ap-northeast-1'}); /** * S3 ObjectCreated event * * @param {object} event */ module.exports.create = async (event) => { const bucket = event.Records[0].s3.bucket.name; const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' ')); // CloudWatch上のログを確認する cosole.log(`${bucket}/${key}が作成されました`); // ここにやりたいことを書いていく };
デプロイ
特別な設定や手順はありません。楽ちんですねー。
$ sls deploy
最後に実際にS3にファイルをアップロードして挙動の確認を行えば完了です。