CloudFormationを使ってCloudWatch Eventsでスケジュール起動されるlambdaをデプロイする

# はじめに
以下記事ではCloudFormationを使ってlambda単体をデプロイする方法について記載した。
[CloudFormationを使ってlambda(node.js)環境を構築する](https://qiita.com/kyuaz/items/c1374c8d0711fd400aaa)

ただlambdaを使う上で単体で、つまり手動で実行するケースは少ない。ほとんどの場合、lambdaを実行させるためのトリガーとセットで使うことになる。そのため本記事ではトリガーとして、CloudWatchEventsを指定してlambda本体と合わせてデプロイする方法について説明する。

# Lambdaをスケジュール起動するためのテンプレート記述
lambdaをスケジュール起動するための、CloudFormationのテンプレート記述は以下2つが必要になる。

- AWS::Events::Rule
- AWS::Lambda::Permission

AWS::Events::Ruleは、CloudWatchEventsの設定であり、AWS::Lambda::Permissionは実行したいlambdaとCloudWatchEventsを紐づけるための設定である。

以下、それぞれのテンプレート記述について説明し、最後に全体のテンプレートファイルを示す。

# AWS::Events::Rule
CloudWatchEventsのテンプレート記述について以下に抜粋。

```yaml:template.yaml(抜粋)
  LambdaScheduleEvent:
    Type: AWS::Events::Rule
    Properties:
        Description: ’schedule event for lambda’
        ScheduleExpression: 'cron(0/1 * * * ? *)'
        State: ENABLED
        Targets:
          - Arn: !GetAtt HelloworldLambdaFunction.Arn
            Id: ScheduleEvent1Target
```

1分おきにHelloworldLambdaFunctionというlambdaを実行するCloudWatchEventsである。なおHelloworldLambdaFunctionは、同じテンプレートファイル内で定義したlambdaを設定する任意の名前である。

GetAttとはテンプレートファイル内で使用できる組み込み関数の1つであり、テンプレートファイル内で定義されたリソースとリソースの属性を指定して、その値を取得することができる。

GetAttの公式ドキュメントの説明は以下参照。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html

またAWS::Events::Ruleのテンプレート記述のリファレンスは以下参照。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-events-rule.html


# AWS::Lambda::Permission
lambdaとCloudWatchEventsを紐づけるための設定に関するテンプレート記述は以下の通りである。

```yaml:template.yaml(抜粋)
  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !Ref HelloworldLambdaFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt LambdaScheduleEvent.Arn
```

Lambdaの呼び出し元は、CloudWatchEvents(events.amazonaws.com)として同一テンプレート内で定義したLambdaScheduleEventのARNを指定する。また、起動するlambda(FunctionName)は組み込み関数の1つであるRef関数を使い、同一テンプレート内で定義したlambdaを取得する。

AWS::Lambda::Permissionの公式リファレンスは以下参照
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html


# テンプレートファイル全体
上記、AWS::Events::Rule、AWS::Lambda::Permissionを追加して完成したテンプレートファイルは以下の通り。

```yaml:template.yaml
AWSTemplateFormatVersion: 2010-09-09
Resources:
  HelloWorldLambdaFunction:
    Type: AWS::Lambda::Function
    Properties: 
      FunctionName: lambda-function-name
      Handler: index.handler
      Role: arn:aws:iam::1234567890:role/LambdaRole
      Runtime: nodejs8.10
      Timeout: 10
      Code:
        S3Bucket: bucket-name
        S3Key: app/deploy/lambda.zip
      Tags:
        -
          Key: COST
          Value: app-lambda
  LambdaScheduleEvent:
    Type: AWS::Events::Rule
    Properties:
        Description: ’schedule event for lambda’
        ScheduleExpression: 'cron(0/1 * * * ? *)'
        State: ENABLED
        Targets:
          - Arn: !GetAtt HelloworldLambdaFunction.Arn
            Id: ScheduleEvent1Target
  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !Ref HelloworldLambdaFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt LambdaScheduleEvent.Arn
```

本テンプレートファイルでCloudFormationでスタックを作成（デプロイ）すると、1分ごとに起動されるlambdaが立ち上がる。

# CodeBuldからaws cliを使ってCloudFormationを実行する場合

参考までに、もしCodeBuildからaws cli経由でCloudFormationを実行して、本記事の構成でデプロイする場合、CodeBuildに以下ポリシーを付けたRoleを付与する必要がある。

- CloudWatchEventsFullAccess
- lambda:* (カスタムポリシー)
- AmazonS3FullAccess
- iam:PassRole (カスタムポリシー)
- cloudformation:CreateStack (カスタムポリシー)
- cloudformation:DeleteStack (カスタムポリシー)
- cloudformation:UpdateStack (カスタムポリシー)
- cloudformation:DescribeStacks (カスタムポリシー)

なおCodeBuildを使ったデプロイについては以下記事に記載している。
[aws CodeBuildを使ってlambda(node.js)環境をテスト→デプロイする](https://qiita.com/kyuaz/items/604d11b8af1921112f99)

以上、参考まで。
 

# まとめ

本記事ではCloudFormationを使ってスケジュール起動するlambdaのデプロイする方法について記載した。

# awsで開発作業を自動化するのまとめ記事
本記事はawsで開発作業を自動化するシリーズの1つです。その他の記事については以下を参照ください。
[aws環境でnode.js、lambda、CodeCommit、CodeBuild、CloudFormation、CodePipelineを使って開発作業を自動化する](https://qiita.com/kyuaz/items/704efb51bce59f21c002)