Lambda関数をCloudFormationでデプロイする(YAML)。コードベタ書きとS3からのダウンロード

もくじ

はじめに

やること

Pythonのプログラムを記述したLambda関数を、CloudFormationでデプロイします。

CloudFormationのコードはYAMLで記述し、コード中の各プロパティについて、Lambda関数のどの設定値に紐付くか記載します。

また、YAMLコードの中にPythonコードをベタ書きするパターンと、PythonコードをS3にzipファイルで配置しておき、そこから参照するパターンを記載します。

対象の読者

  • CloudFormationをとりあえず使ってみたい。
  • CloudFormationでLambda関数をデプロイしたい。
  • Lambda関数のハンドラーの意味を知りたい。(本記事で少し詳しく解説しています)

Lambda関数

設定値

今回スタックから作成するLambda関数の設定値は以下のようになっています。

項目設定値
関数名デプロイ時に入力する。
Lambdaハンドラーindex.lambda_handler
Lambda関数の説明Function that put items to DynamoDB
ランタイムPython 3.9
メモリ128 MB
タイムアウト5秒
アーキテクチャx86_64
エフェメラルストレージ512 MB
ロールCloudWatch Logsに書き込む権限を付与。
DynamoDBへのすべての操作を許可。

CloudFormationテンプレート①(Pythonコードベタ書き)

YAMLコード

スタック作成に使うYAMLで記述したテンプレートは以下で、「Lambda.yml」という名前で保存しました。

---
AWSTemplateFormatVersion: 2010-09-09
Description: "IaC for Lambda"

Parameters:
  NameOfFunction:
    Type: String
    Description: "Name of Lambda Function"

Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Ref NameOfFunction
      Description: "Function that put items to DynamoDB"
      Runtime: "python3.9"
      MemorySize: "128"
      Timeout: "5"
      Role: "arn:aws:iam::XXXXXXXXXXXX:role/service-role/putDynamoFunc-role-l6trp0uq"
      Handler: index.lambda_handler
      Architectures: [ "x86_64" ]
      EphemeralStorage:
        Size: "512"
      Code:
        ZipFile: |
          import json
          import boto3
          
          def lambda_handler(event, context):
              # Lambdaのテストから受け取ったデータを取り出して変数に格納
              email = event['email']
              name = event['name']
              gender = event['gender']
              inquiry = event['inquiry']

              # DynamoDBに投入するためのアイテムをセット。JSONを作成して変数に格納
              DynamoItems = {
                  'Email': email,
                  'Name': name,
                  'Gender': gender,
                  'Inquiry': inquiry
              }
              
              # DynamoDBにデータを投入
              table = boto3.resource('dynamodb').Table('inquiry-table')
              response = table.put_item(
                  Item = DynamoItems
              )
              
              return {
                  'statusCode': 200,
                  'body': json.dumps(response)
              }

コード解説

コードのプロパティを、上から解説します。

AWSTemplateFormatVersion

形式バージョンになり、固定値になります。「2010-09-09」を指定します。

形式バージョン

Description

CloudFormationのスタックの説明になります。CloudFormationダッシュボードのスタックの説明欄に記載されます。

Parameters

CloudFormationでスタックを作成するときに、ユーザが手動で指定するパラメータを定義します。

ここでは、「Lambda関数の名前」をスタック作成時に指定するようにしています。ユーザーが入力した文字列(Lambda関数名)は、ResourcesプロパティのFunctionNameで参照しています。(後述)

Resources

Type

Lambda関数をデプロイするため、「AWS::Lambda::Function」を指定しています。

FunctionName

Lambda関数の関数名です。ユーザーがParametersプロパティで入力した文字列を「!Ref」で参照して受け取っています。

Runtime

Lambda関数のランタイムを指定します。ここでは「Python 3.9」です。

MemorySize

Lambda関数のメモリです。ここでは128MBにしています。

Timeout

Lambda関数のタイムアウトです。ここでは5秒です。

Role

Lambda関数にアタッチするIAMロールです。ARNで指定しています。IAMロールの内容は本記事に書いていませんが、ざっくり言うとCloudWatch Logsへの書き込み権限とDynamoDBへの全権限を付与しています。

Handler

Lambda関数のハンドラーを指定します。

Lambda関数のハンドラーとは、Lambda関数が呼び出されたときに、どのファイルのどの関数を呼び出すか定義したものとなります。

例えば、以下のようにハンドラーが「lambda_function.lambda_handler」と設定されていたときは、「lambda_function.py」の中の「lambda_handler」関数が呼び出されることになります。

Python の Lambda 関数ハンドラー

Lambda関数のCloudFormationでデプロイすると、Pythonファイル(上でいう「lambda_function.py」)は「index.py」となるため(後述)、コード内のHandlerには「index.lambda_handler」としています。

Architectures

Lambda関数のアーキテクチャを記述します。「arm64」か「x86_64」を記述します。ここでは「x86_64」を指定しています。

EphemeralStorage

Lambda関数の「/tmp」のサイズです。ここでは512MBを指定してみました。

Code

Lambda関数にデプロイするパッケージを記述します。選択肢は以下のいずれかです。

  • ImageUri(ECRに保存したコンテナイメージを指定する)
  • S3Bucket(S3バケットに保存したパッケージを指定する)
  • S3Key(パッケージのS3のキーを指定する)
  • S3ObjectVersion(パッケージのバージョンを指定。パッケージがバージョン管理されている場合に使用)
  • ZipFile(ソースコードをベタ書きする場合。PythonかNode.js。「index」というファイル名でデプロイする)

ここでは「ZipFile」を記述しています。

ですので、YAMLのコード上にPythonコードをベタ書きしています。そして、index.pyというファイル名でLambda関数にデプロイされるため、Lambdaハンドラーは「index.lambda_handler」となっています(繰り返しですが)。

デプロイ

デプロイします。

スタック名は「Stack-Lambda」で、Lambda関数名は「testFunc」としています。

成功しました。

テスト

テストしてみます。

デプロイしたLambda関数を動かすと、別の記事で作成したDynamoDBにアイテムがプットされます。

Googleフォームからデータを送信してDynamoDBに登録する

デプロイしたLambda関数から以下のようなJSONを渡してテストします。

200ステータスが返ってきました。DynamoDBのテーブルを見てみましょう。

テストで指定したJSONにある値がDynamoDBテーブルにPUTされています。

テストも成功です。

CloudFormationテンプレート②(PythonコードをS3に配置)

今度はPythonコードをCloudFormationテンプレートにベタ書きではなく、S3にzipファイルで配置します。

CloudFormationでデプロイするときに、S3のzipファイルから読み込みます。

Pythonコードをzip化

手順は下記サイトに書いてあります。

.zip ファイルアーカイブで Python Lambda 関数をデプロイする

「index.py」のコードは以下になります。

import json
import boto3

def lambda_handler(event, context):
    # Lambdaのテストから受け取ったデータを取り出して変数に格納
    email = event['email']
    name = event['name']
    gender = event['gender']
    inquiry = event['inquiry']

    # DynamoDBに投入するためのアイテムをセット。JSONを作成して変数に格納
    DynamoItems = {
        'Email': email,
        'Name': name,
        'Gender': gender,
        'Inquiry': inquiry
    }
    
    # DynamoDBにデータを投入
    table = boto3.resource('dynamodb').Table('inquiry-table')
    response = table.put_item(
        Item = DynamoItems
    )
    
    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }

「index.py」を「package.zip」にパッケージ化しました。

% pwd
/Users/atsushi/Document/AWS/Python
% 
% ls -l
total 8
-rw-r--r--  1 atsushi  staff  742  5 24 17:14 index.py
% 
% zip package.zip index.py 
  adding: index.py (deflated 43%)
% 
% ls -l
total 16
-rw-r--r--  1 atsushi  staff  742  5 24 17:14 index.py
-rw-r--r--  1 atsushi  staff  590  5 24 17:20 package.zip
% 

zipファイルをS3にアップロード

「s3://bucket-atsushi-00/python/」ディレクトリをS3上に作成して、そこにzipファイルをアップロードしました。

YAMLコード修正

修正後のYAMLコードは以下になります。

---
AWSTemplateFormatVersion: 2010-09-09
Description: "IaC for Lambda"

Parameters:
  NameOfFunction:
    Type: String
    Description: "Name of Lambda Function"

Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Ref NameOfFunction
      Description: "Function that put items to DynamoDB"
      Runtime: "python3.9"
      MemorySize: "128"
      Timeout: "5"
      Role: "arn:aws:iam::XXXXXXXXXXXX:role/service-role/putDynamoFunc-role-l6trp0uq"
      Handler: index.lambda_handler
      Architectures: [ "x86_64" ]
      EphemeralStorage:
        Size: "512"
      Code:
        S3Bucket: "bucket-atsushi-00"
        S3Key: "python/package.zip"

修正箇所はCodeプロパティのみです。「ZipCode」から「S3Bucket」と「S3Key」に変えています。

S3Bucket」にはZip化したPythonプログラムが保存されているS3バケット名を記述します。

S3Key」には、Zip化したPythonプログラム(ここではzipファイル)までのパスを記述します。「bucket-atsushi-00」バケットの下に「python」ディレクトリを作成しているので、ここでは「python/package.zip」となっています。

デプロイとテスト

ここから先は、「CloudFormationテンプレート①(Pythonコードベタ書き)」の時と同じです。

省略いたします。

参考サイト

CloudFormation テンプレートが肥大化したので分割したいです。方法を教えてください

AWS::Lambda::Functionのプロパティ

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメントする

コメントは日本語で入力してください。(スパム対策)

CAPTCHA

もくじ
閉じる