はじめに
こんにちは。孔子の80代目子孫兼技術5課の孔です。やっと梅雨が終わりましたね!日光で干した洗濯物の方が気持ちよく着れるので、とても嬉しいですが、ここ3ヶ月間家からほとんど出てないのでそんなに意味なかったな…とダークモードになっています。コロナ終息のために、頑張りましょう!
今日はServerless Framework + SNSというトピックを持ってきました。例えば、CloudWatch Eventsを使ってLambdaを毎日朝9時に走らせるような処理をするとしいて、毎日朝9時にLambdaが正常に起動したかどうか確認しにAWSコンソールを開くのはとても面倒な作業ですね。そこでLambdaが失敗した時にSNSで自動的に通知して、Slackでそのメッセージを受け取るような構成を作れば、毎日確認する作業がなくなってとても楽になります。
そのような構成とサンプルコードを、Serverless Frameworkでデプロイしてみよう!というのが本日のテーマとなります。Serverless FrameworkはAWS上にLambdaを中心にいろいろなAWSリソースをデプロイできるサービスとなります。それでは、実際やってみましょう。
※ Serverless Frameworkを触ったことのある方を対象としているため、基本的な操作については説明を割愛しています。
まずはPythonコード
2つのコードを用意しました。Slackに投稿するためのLambdaコード(notify_to_slack.py)と、SNSにpublishするコード(publisher.py)となります。
# notify_to_slack.py import urllib3 import json http = urllib3.PoolManager() def lambda_handler(event, context): url = "https://hooks.slack.com/services/XXXXX...." msg = { "channel": "#slack_channel", # Slackのチャンネル名 "username": "Lambdaからのお知らせ", # bot名 "text": event['Records'][0]['Sns']['Message'], "icon_emoji": "emoji" # botのアイコン } encoded_msg = json.dumps(msg).encode('utf-8') resp = http.request('POST', url, body=encoded_msg) return { "message": event['Records'][0]['Sns']['Message'], "status_code": resp.status, "response": resp.data }
urlの中には、SlackのWebhookを入力してください。msgの中身のtext以外のものも適切なものに変えてください。
# publisher.py import boto3 from os import getenv def lambda_handler(event, context): try: raise Exception('エラー発生!') except: client = boto3.client('sns') TOPIC_ARN = getenv('SNS_TOPIC') msg = 'テストです' subject = 'てすてす' response = client.publish( TopicArn=TOPIC_ARN, Message=msg, Subject=subject ) return response
こちらのコードはclientにSNSを指定し、publishというAPIを使っています。publish APIは名前通りSNSのTopicにメッセージをpublishするAPIとなります。
これで、コードの準備は完了です。それではServerless FrameworkでSNSおよびLambda関数をデプロイしてみましょう!
serverless.ymlを記入する
serverless.ymlの中身は以下となります
service: sns-test provider: name: aws runtime: python3.8 stage: dev region: ap-northeast-1 functions: publisher: handler: publisher.lambda_handler environment: SNS_TOPIC: !Ref FailureTopic role: publishToSns notify_to_slack: handler: notify_to_slack.lambda_handler events: - sns: arn: !Ref FailureTopic topicName: FailureTopic resources: Resources: FailureTopic: Type: AWS::SNS::Topic Properties: TopicName: FailureTopic publishToSns: Type: AWS::IAM::Role Properties: RoleName: PublishToSNSRole AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: PublishToSNSPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - sns:* Resource: - !Ref FailureTopic
まずfunctionsで先ほど作成した2つのコードをLambdaにデプロイしています。notify_to_slackの方で、eventsの中にSNSを指定していますが、こちらがLambdaのトリガーイベントとなります。
トリガーとして例えばAPIGWやS3イベントがあると思いますが、そのようなトリガーの設定をこちらのeventsから設定します。
また、resourcesの中でSNSトピックを作成しています。Serverless Frameworkを使ってリソースをデプロイする際にはこちらのresources項目を使います。このように作成したSNSトピックをnotify_to_slackのSNSイベント項目に!Ref FailureTopic
として指定することで、Serverless FrameworkがデプロイしたSNSトピックをデプロイされるLambdaが参照できるようになります。
デプロイしてからpublisher.pyをテストなどで起動してみると、無事Slackに指定したチャンネルにメッセージが飛んでくることが確認できるかと思います。
最後に
Serverless Frameworkはとても便利なデプロイツールですのでどんどん使ってみましょう!特に今回触れたeventsは、イベントドリブンで発火することの多いLambdaにとってとても高頻度で使用される機能ですので、覚えておくと役に立つことが多いかと思います。