スケジュール起動するLambda関数をCloudFormationで作成してみた

2017.08.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

AWSチームのすずきです。

2017年8月CloudFormationのアップデートにより、リソースタイプとして「AWS::Lambda::Permission」が追加され、 Lambda関数の起動トリガーを設定可能になりました。

今回、CloudWatch Events のスケジュールで起動するLambda関数を、CloudFormationで設置する機会がありましたので、紹介させていただきます。

CloudFormationテンプレート

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Scheduled Lambda Sample'
Parameters:
  targeturl:
    Description: URL
    Type: String
    Default: https://www.google.co.jp
Resources:
  ScheduledRule:
    Type: AWS::Events::Rule
    Properties:
      Description: ScheduledRule
      ScheduleExpression: 'cron(0/2 * * * ? *)'
      State: ENABLED
      Targets:
      - Arn: !GetAtt 'LambdaFunction.Arn'
        Id: TargetFunctionV1
  PermissionForEventsToInvokeLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref 'LambdaFunction'
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      SourceArn: !GetAtt 'ScheduledRule.Arn'
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: /
      Policies:
      - PolicyName: root
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource: '*'
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Sub |
          from __future__ import print_function
          import urllib.request
          import os
          import time
          def handler(event, context):
            try:
              #Get start time
              starttime = time.time()
              #Get URL from environment variable
              url = os.environ['targeturl']
              #Open URL
              r = urllib.request.urlopen(url)
            except HTTPError as e:
              print('error code:', e.code)
            except URLError as e:
              print('error reason:', e.reason)
            else:
              #Get elapsed time
              elapsedtime = time.time() - starttime
              #report
              ## real URL of the page fetched
              print('geturl:', r.geturl())
              ## page length (not Content-length header)
              print('length:', len(r.read()))
              ## Execution time
              print('elapsedtime:', str(elapsedtime))
              ## headers sent by the server
              #print(r.info())
      Runtime: python3.6
      MemorySize: 128
      Timeout: 30
      Description: 'Scheduled Lambda Sample (python3 urlopen)'
      Environment:
        Variables:
          'targeturl': !Ref 'targeturl'
      Tags:
      - Key: Name
        Value: 'ScheduledLambdaSample'
      - Key: CloudformationArn
        Value: !Ref 'AWS::StackId'

Cloudwatchイベントとトリガー設定は、公式ドキュメントのサンプルを参考に、Cron形式指定で実行間隔2分とする設定を行いました。

LambdaはWeb監視を実施する関数を用意しました。

CloudFormationのパラメータとして指定したURLをLambdaの環境変数経由で受け取り、Python3のurllibを利用してチェックしています。

【アップデート】AWS Lambdaで環境変数を使えるようになりました!!!

AWS LambdaがPython3.6に対応したので使ってみた

まとめ

YAMLの短縮記法や、Lambdaの環境変数機能を利用する事により、AWSコンソールのインライン編集画面で動作確認済みのコードをCloudFormationテンプレートに反映させる事も可能です。

lambda-permission-cfn-01

Lambda関数の実行環境を管理する各種フレームワークがありますが、管理手段の一つとしてCloudFormationをご活用ください。

尚、グローバルに公開されているサービスのWeb監視の実現には、Route53で提供されるヘルスチェックの利用がお薦めです。

Route53ヘルスチェックを利用したポート監視