この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どうも!大阪オフィスの西村祐二です。
この記事はAWS LambdaとServerless #1 Advent Calendar 2019の14日目 の記事です。
個人的に今後良く利用しそうだなと思っているサービスの一つであるEventBridgeとLambdaを連携させるためのServerless Frameworkの設定方法をまとめていきたいと思います。
EventBridgeはLambdaを挟まなくても良い場面が多そうではありますが、やっぱり要件満たせないからLambdaを挟むこともたぶん発生すると思うので、そういった場面で即座に対応できるようにしておきたいと思ったのが執筆の動機です。
また、EventBridgeの挙動の確認や、サービス理解の勉強にもお手軽でちょうど良いかなとも思っています。
Serverless Frameworkを使うのは、個人的な好みです。AWS SAMなど他のツールでの設定方法も別の機会にまとめてみたいと思います。
Amazon EventBridgeとは
Amazon EventBridge は、独自のアプリケーション、SaaS (Software-as-a-Service) アプリケーション、AWS のサービスからのデータを使用してアプリケーションどうしを簡単に接続することを可能にするサーバーレスイベントバスです。EventBridge は、Zendesk、Datadog、Pagerduty などのイベントソースからリアルタイムデータのストリームを配信し、そのデータを AWS Lambda などのターゲットにルーティングします。お客様は、データの送信先を判断するためのルーティングルールを設定して、すべてのデータソースにリアルタイムで反応するアプリケーションアーキテクチャを構築できます。EventBridge では、イベントの取り込みと配信、セキュリティ、承認、エラー処理が自動的に行われるため、イベントドリブンアーキテクチャを簡単に構築することができます。
詳細は下記のサービスページをご参照ください。
https://aws.amazon.com/jp/eventbridge/
EventBridgeの概要図をみるとイメージつきやすいかと思います。イベントソースには、AWSの各サービス、SaaSアプリ、独自アプリなどを用いることができ、Ruleによってイベントのフィルタリングをした上でAWS Lambda、Amazon Kinesis Data Firehose、Amazon SNS、またはそれ以外のターゲットに流すことができます。
※サービスサイトより引用
また、EventBridgeはCloudWatch Eventsと同じことができるのですが、内部ではCloudWatch Eventsと同じサービスAPIとエンドポイント、同じ基盤となるサービスインフラストラクチャを使用しており、将来的に、Amazon CloudWatch Eventsの名称は Amazon EventBridgeに置き換えられる予定であるとのことです。
https://aws.amazon.com/jp/eventbridge/faqs/
環境
Serverless Framework:1.59.3
Node.JS:12.13.0
試してみる
事前準備
Serverless Frameworkを使ってプロジェクトを作っておきます。
$ mkdir eventbrige-demo
$ cd eventbrige-demo
$ sls create -t aws-nodejs -n eventbrige-demo
event
をログ出力するように設定します。
handler.js
'use strict';
module.exports.hello = async event => {
console.log(event);
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event
},
null,
2
)
};
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
私はいつも東京リージョンをつかっているので、リージョン情報を追加しておきます。
serverless.yml
service: eventbrige-demo
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-1
functions:
hello:
handler: handler.hello
既存のイベントバスにルールを作成する
EventBridgeの既存のイベントバスとは下記のようにはじめから用意されているdefault
というバスを指します。これに対してルールを作成していきます。
EventBridgeからLambdaを定期実行
EventBridgeはCloudWatch Eventsと同じように一定期間ごとにイベント実行することができますので、その設定を行います。
下記設定では10分に一回Lambdaが実行され、{key1: value1}
がペイロードとして渡されてるという設定です。
serverless.yml
service: eventbrige-demo
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-1
functions:
hello:
handler: handler.hello
events:
- eventBridge:
schedule: rate(10 minutes)
input:
key1: value1
下記コマンドでデプロイします。
$ sls deploy
デプロイが完了したらマネコンから確認してみましょう。
「eventbrige-demo-dev-hello-rule-1」というルールが作成されていました。
LambdaのトリガーのところにはEventBridgeではなく、「CloudWatch Events」が設定されています。これは内部でCloudWatch Eventsと同じサービスAPIとエンドポイントを使用しているからだと思われます。
なぜか2つのLambdaが作られている
Lambdaを確認すると、知らないLambda「eventbrige-demo-dev-custom-resource-event-bridge」ができていました。
これはServerless Frameworkの内部でカスタムリソースをつかってEventBridgeを構築しているからのようです。
CloudFormationはEventBridgeのリソースに対応しているので、今後カスタムリソースを使った構築方法は変更されるかもしれませんね。
イベントパターンマッチング設定
あるパターンにマッチしたイベントが実行されたらLambdaを起動するようなこともできます。
下記ではcloudformationが実行されるとLambdaが実行されるというようなパターンを記載しています。
serverless.yml
service: eventbrige-demo
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-1
functions:
hello:
handler: handler.hello
events:
- eventBridge:
pattern:
source:
- aws.cloudformation
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- cloudformation.amazonaws.com
仕組みはsource
で対象のソース(今回はAWSサービスのCloudFormation)を指定し、detail-type
の値をAWS API Call via CloudTrail
にすることでCloudTrailによってキャプチャされた情報でトリガーする設定ができます。
マネコンで設定する際は下記の画像と同じことを設定しています。
どのようにパターンを記載するかはマネコンから確認するかこちらのドキュメントから確認する方法しかなさそうです。未確認ですがAWS CDKなら、エディタ補完が効くのでパターンの記載は楽そうだなと思います。
上記設定をしたときLambdaでは下記のようなログが出力されます。特にCloudFormation側の設定などはいらないので簡単にイベントドリブルな仕組みを作ることができます。
{
version: '0',
id: 'xxxxxxxxxxxxxxxxxxx',
'detail-type': 'AWS API Call via CloudTrail',
source: 'aws.cloudformation',
account: 'xxxxxxxxxxxxxxxxxxx',
time: '2019-12-12T14:08:01Z',
region: 'ap-northeast-1',
resources: [],
detail: {
eventVersion: '1.05',
userIdentity: {
type: 'AssumedRole',
principalId: 'xxxxxxxxxxxxxxxxxxx',
arn: 'arn:aws:sts::xxxxxxxxxxxxxxxxxxx:assumed-role/xxxxxxxxxxxxxxxxxxx',
accountId: 'xxxxxxxxxxxxxxxxxxx',
accessKeyId: 'xxxxxxxxxxxxxxxxxxx',
sessionContext: [Object]
},
eventTime: '2019-12-12T14:08:01Z',
eventSource: 'cloudformation.amazonaws.com',
eventName: 'UpdateStack',
awsRegion: 'ap-northeast-1',
sourceIPAddress: 'xxxxxxxxxxxxxxxxxxx',
userAgent: 'aws-sdk-nodejs/2.588.0 darwin/v12.13.0 promise',
requestParameters: {
templateURL: 'https://s3.amazonaws.com/eventbrige-demo-dev-serverlessdeploymentbucket-1s2yxjjdltahv/serverless/eventbrige-demo/dev/xxxxxxxxxxxxxxxxxxx-2019-12-12T14:08:02.967Z/compiled-cloudformation-template.json',
parameters: [],
stackName: 'eventbrige-demo-dev',
capabilities: [Array]
},
responseElements: {
stackId: 'arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxxxxxxxxx:stack/eventbrige-demo-dev/xxxxxxxxxxxxxxxxxxx'
},
requestID: 'xxxxxxxxxxxxxxxxxxx',
eventID: 'xxxxxxxxxxxxxxxxxxx',
eventType: 'AwsApiCall'
}
}
独自イベントバスを作成する
既存のバスのdefault
ではなく独自のバスを作成する場合は、eventBus
というプロパティを設定し、バス名を指定することで独自のイベントバスを作成して、ルールを設定してくれます。
serverless.yml
service: eventbrige-demo
provider:
name: aws
runtime: nodejs12.x
region: ap-northeast-1
functions:
hello:
handler: handler.hello
events:
- eventBridge:
eventBus: custom-saas-events
pattern:
source:
- saas.external
既存のイベントバスを使用する
既存のイベントバスを使用する場合はeventBusにARN
を設定する必要があります。アカウントIDはプラグインを使うか外部のJSファイルから取得する方法が良いでしょう。
serverless.yml
・・・
custom:
accountId:
${file(./account.js):getAccountId}
・・・
- eventBridge:
eventBus: arn:aws:events:${self:provider.region}:${self:custom.accountId}:event-bus/custom-private-events
pattern:
source:
- "aws.ec2"
detail-type:
- "EC2 Instance State-change Notification"
detail:
state:
- pending
inputTransformer:
inputPathsMap:
eventTime: "$.time"
inputTemplate: '{"time": <eventTime>, "key1": "value1"}'
account.js
const { STS } = require('aws-sdk');
const sts = new STS();
module.exports.getAccountId = async () => {
// Checking AWS user details
const { Account } = await sts.getCallerIdentity().promise();
return Account;
};
さいごに
Serverless FrameworkでEventBridgeとLambdaを連携させる設定をみていきました。
数行の設定で簡単にEventBridgeとLambdaを連携させることができてとても楽チンだと思います。
ただ、まだプレビューですがスキーマレジストリなどの設定はできないようなので今後のアップデートに期待したいと思います。
このブログの作成を通じてEventBridgeの挙動や設定方法、またServerless Frameworkが内部でカスタムリソースを使っているなどの挙動の理解などいろいろ勉強になりました。
興味のある方は試してみてはいかがでしょうか。
機会があれば、AWS SAMなど他のツールでの設定方法や挙動などまとめてみたいと思います。
誰かの参考になれば幸いです。