🐈

AWS CloudFormationを触ってみる #2 EventBridge Lambda SNS

2022/07/09に公開

はじめに

こんにちは 中村です!

前回 CloudFormationをとりあえず触ってみる記事を書きました
今回はそれより少し複雑な構成をデプロイしてみようと思います

構成

以下のような構成となります。
EventBridgeが2分おきにLambdaを発火し、Lambda、SNSを通じてメールを飛ばすという内容です。

テンプレート

以下のテンプレートファイルをローカルに保存してください

template.yml
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  ResourceName:
    Type: String
  Email:
    Type: String

Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties: 
      Handler: index.lambda_handler
      Code:
        ZipFile: !Sub |
          import boto3
          import os
          import datetime
          client = boto3.client('sns')
          topic_arn = os.environ['TopicArn']
          def lambda_handler(event, context):
              dt_now = datetime.datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')
              params = {
                  'TopicArn': topic_arn,
                  'Subject': 'Lambda SNS メール送信 '+ str(dt_now),
                  'Message': 'Message\n\nLambda -> SNSでメール送ったよ\n届いた?\n' + str(dt_now)
              }
              client.publish(**params)
      FunctionName: !Sub ${ResourceName}-function
      Runtime: python3.9
      Environment: 
        Variables:
          TopicArn : !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${ResourceName}-sns
      Role: !GetAtt
        - LambdaExecutionRole
        - Arn

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${ResourceName}-function-execution-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${ResourceName}-function-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${ResourceName}-function:*
                Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - logs:CreateExportTask
                  - s3:GetBucketAcl
                  - s3:PutObject
        - PolicyName: !Sub ${ResourceName}-function-nsn-policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Resource: !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${ResourceName}-sns
                Effect: Allow
                Action:
                  - sns:Publish

  SnsTopic:
    Type: AWS::SNS::Topic
    Properties: 
      DisplayName: !Sub ${ResourceName}-sns
      FifoTopic: false
      TopicName: !Sub ${ResourceName}-sns
      Subscription:
        - Endpoint: !Ref Email
          Protocol: email

  EventBridgeRule:
    Type: AWS::Events::Rule
    Properties: 
      EventBusName: default
      Name: !Sub ${ResourceName}-eventbridge-rule
      ScheduleExpression: cron(0/2 * * * ? *)
      State: ENABLED
      Targets: 
        - Arn: !GetAtt LambdaFunction.Arn
          Id: LambdaFunction

  PermissionForEventsToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref LambdaFunction
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt 'EventBridgeRule.Arn'

CloudFormationを実行

上記テンプレートをローカルに保存した上で、
こちらを参考にCloudFormationを作成してください

今回は2つのパラメータを指定します

  • Email
  • ResourceName

テンプレートファイルに以下のように記述する事で、作成時に自由に値を指定できるパラメータを設定することができます

template(抜粋).yml
Parameters:
  ResourceName:
    Type: String
  Email:
    Type: String

無事にスタックが作成されました

作成されたリソースを確認

リソースがちゃんと作成されたか確認します

  • EventBridgeルール

  • Lambda関数

  • SNSトピック

ちゃんと作成されていますね!(^^)b

スタックのパラメータで指定したメールアドレスにSNSからサブスクリプション承認のメールがきているので、リンクをクリックして承認します。(これでSNSからメールが受け取れるようになります)

動作確認

作成したリソースがちゃんと意図した通り動いているか確認します。

指定した頻度でメールが届いています (2分おきは流石に送り過ぎかなぁww)

メール本文もLambdaで指定した通りですね!

リソース削除

さて、2分おきに迷惑メールが来てウザいのでw リソース削除しちゃいます。
それぞれのリソースを削除することも可能ですが、CloudFormationスタックで作ったものはCloudFormationスタックごと削除する方が無難かと思います。

対象のスタックを選択して「削除」をクリックします

テンプレートファイル作成するにあたって

CloudFormationユーザーガイド

基本的にはAWS公式のCloudFormationユーザーガイドと睨めっこしながら作成していきます

左メニューのテンプレートリファレンスリソースおよびプロファイルのリファレンスを開くと、AWSサービス毎のテンプレートの書き方が解説されています

エラーでコケまくる

筆者は何度もエラーでコケまくり、テラテイルで質問してみたり、Twitterで教えて頂いたりしました
皆様ありがとうございます!!
https://twitter.com/nakam_aws/status/1525374167012413441

Lambdaソースコードはどうするのか

CloudFormaitonでLambdaを作成する場合はソースコードはファイルをzip化してS3に保存しなければいけないと言う旨の記事が多かったのですが、そんなの面倒くせぇ!絶対嫌だ!
と言うことでテンプレートファイルに直接コードを書く方法が無いか探しました。
ありました。さすがクラメソさんですね。
https://dev.classmethod.jp/articles/check-when-creating-cloudwatchevents-and-lambda-with-cloudformation/

おわりに

yaml形式で書くのは初めてだった為、なかなか苦労しました。
当たり前かもですが、テンプレートを作成するのが時間がかかりますが、作っちゃえばそれを使いまわせるのがいいですね。
さらにリソース名や設定値をパラメータを使ってデプロイ時にカスタマイズできるので、自由度が高いと感じました
今後もっと活用していきたいと思います!

ここまで読んで頂きありがとうございました!!

Discussion