🐸

AWS SAM を用いて複数のlambda関数をコンテナ開発する

2024/02/26に公開

はじめに

lambda関数のローカル開発が便利だったので、記事にしてみました。

目的

プロダクトのAWS Lambda関数が増えるとGUIコンソール上で管理するのが難しくなる。一方でプライベートサブネットでのDB接続機能を具備するような関数の場合、コンテナ化すると毎回イメージを更新しないとLambdaのテスト機能を利用できない。dockerイメージに含ませたくない環境変数の場合、手動で設定が面倒&設定ミスの可能性を0にできない

  • 1.コンテナ管理
  • 2.テスト機能をローカルでも実行可能
  • 3.lambda関数自体の設定を自動化(デプロイの自動化)

上記を目指して、AWS SAMを勉強した内容を記録する

やりたいこと(完成系)

  • コードをgitで管理
  • 環境は同一のdockefile(読者様の求められる要件次第だとは思います。)
  • LambdaリソースをcloudFormationテンプレートで管理
  • テストはメンバーのローカル環境で実施(sam local invoke)

上記を満たすように、下記ディレクトリ構造を目指す。

.
└── projects/
    ├── events
    ├── lambda-function-001/
    │   │   └── app.py(lambda_handler関数を含むもの)
    │   └── tests
    ├── lambda-function-002
    ├── lmabda-function-003
    ├── ...
    ├── lib(共通処理)
    ├── dockerfile
    ├── requrements.txt
    ├── samconfig.toml
    └── template.yaml

プロジェクトの開始

まずはAWS SAM CLIをインストールする。公式にインストールページが用意されているので、対応のOSにしたがう。公式サイト
インストールが完了したら,sam initを対象のディレクトリ上で実行する。
対話的に各種設定が可能だが、もちろんオプションを指定可能。
(例:sam init --base-image amazon/python3.11-base)

複数のlambda関数で統一のdockerfileを使用する

[結論]
dockerfileで気にすることはない。必要なパッケージをインストールする。

Dockerfile
# 共通する処理
FROM public.ecr.aws/lambda/python:3.11 as base
COPY requirements.txt ./
RUN python3.11 -m pip install -r requirements.txt -t .
COPY ./* ./

template.yamlに必要な情報

cloudFormationでlambda関数を構成することになるため、cloudFormationテンプレートを記載する。テンプレート全体ではなく、特に利用頻度が高そうな内容に絞って紹介する。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  python3.11

############################################
# 定数宣言
#  yamlで参照するときは、!Ref {変数名}の呼び方にする
# 具体のパラメータの値はsamconfig.tomlのparameter_overridesに渡す
#  parameter_overrides  = ["BUCKETNAME = hoge"]
############################################
Parameters:
  BUCKETNAME: 
    Type: String
    Description: "The name of the S3 bucket"
Resources:
  samLambdaDebugPractice001:#関数名のエイリアスを宣言
    Type: AWS::Serverless::Function  
    Properties:
      PackageType: Image
      ImageConfig:
        - "lambda-function-001/app.lambda_handler"
      Architectures:
        - x86_64
      
      Environment:  # Environmentプロパティの正しい形式
        Variables:
          BUCKET_NAME: !Ref BUCKETNAME
    Metadata:
      Dockerfile: Dockerfile
      DockerContext: ./ # yamlテンプレートファイル視点でdockerファイルが置いてあるdir
      DockerTag: python3.11-v1

ImageConfigの設定

今回は統一的なdockerfileを使用しているため、各関数のイメージで実行するべきCMDをdockerfile以外で指定する必要がある。実行するべきlambda_handler関数へのパスを指定する必要がある。

ImageConfig:
        - "lambda-function-001/app.lambda_handler"

パラメータや環境変数の設定

[結論]
1.環境変数のKeyに関しては、templates.yamlでParametersを指定する。
2.具体のValueはsamconfig.tomlにparameter_overridesを指定する。
[詳細]
例えば共通する環境変数、デプロイする環境ごとの接頭辞(dev,stg,prod)等をまとめて指定することができる。
Parametersで指定した命名(アンダースコア使用不可)をエイリアスとして、!Ref等で参照することができる。


肝心のParametersの指定値だが、samconfig.tomlに記述する。
samconfig.tomlでは環境変数のvalue部分をparameter_overridesをリストで宣言する。
parameter_overridesを

  • [dev.deploy.parameters]
  • [dev.local_invoke.parameters]

のすべてに記載するようにしよう。(環境ごとに設定分けられるのは便利だね。)
parameter_overrides = ["KEY=VALUE","KEY=VALUE"....]の形で記載するが、KEYとVALUEの間にスペース入れるとエラー吐くので注意

template.yaml
Parameters:
  BUCKETNAME: 
    Type: String
    Description: "The name of the S3 bucket"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Resources:
    FunctionName: !Sub "${Prefix}-lambda-function"
    Environment:  # Environmentプロパティの正しい形式
        Variables:
          BUCKET_NAME: !Ref BUCKETNAME
samconfig.toml
[dev.deploy.parameters]
parameter_overrides  = ["BUCKETNAME=YOUR BUCKET NAME"]
[dev.local_invoke.parameters]
parameter_overrides  = ["BUCKETNAME=YOUR BUCKET NAME"]

環境ごとのパラメータの設定

プロダクト開発において、開発、検証、本番の3環境で運用することが多いと思う。それぞれの環境で求められるパラメータのvalueが異なる場合、samconfig.tomlの接頭辞として、それぞれ設定することができる。
接頭辞の指定はsamコマンド実行時のオプションとして-config-envを指定する必要がある。

[dev.deploy.parameters]
~~~
[dev.local_invoke.parameters]
~~~
[stg.deploy.parameters]
~~~
[stg.local_invoke.parameters]
~~~
[prod.deploy.parameters]
~~~
[prod.local_invoke.parameters]
~~~

編集したyamlの文法エラーがないかどうか確認する

あまりyamlに書きなれていないと、余計な空白等によるエラーが発生します。
sam validate --lintで文法チェック可能ですが、不適切な箇所まで指定してくれないので、vscodeのlintツール使いましょう。
AWS Cloudformation用のVSCode設定

作ったSAMテンプレートをベースにビルドする

sam build --debugでビルドする。
ログを出力してくれるので、デバッグが行いやすい。
buildが完了すると以下が実行可能になる。

  • sam local invoke
    ローカル環境にAWSリソース(今回だとlambda関数)を作成し、実行結果を出力する。
  • sam deploy --guided
    新規にデプロイ

SAM local invokeでlambda関数全体としてのテストをする。

sam local invoke {template.yamlで指定した関数のエイリアス名}でlambda関数としてローカル実行できる。
オプションに関しては一部紹介する

  • --profile
    • 検証するアカウントを切り替え可能
  • -config-env
    • samconfig.tomlで指定した環境名を選択できる
  • -e
    • jsonに保存した内容をリクエストに含めて、lambda関数を検証可能。-eのあとにjsonファイルへのパスを指定する。
例: sam local invoke {template.yamlで指定した関数のエイリアス名} --profile {プロファイル名} --config-env dev

この時タイムアウトエラーが連発するようなら、Docker desktopの「Expose daemon on tcp://localhost:2375 without TLS」が有効になっているか確認すること

SAM deploy

sam deploy --guidedで対話形式にデプロイできる。
1つのリポジトリから複数環境にデプロイも可能なので、下記コマンドでdev,stg,prod環境それぞれへのデプロイも可能である。

sam deploy --profile {YOUR PROFILE NAME} --config-env {指定の環境名}--stack-name {任意のstack名}

SecurityErrorが出る場合

対話形式の際に下記の設問にyで答える必要がある。デフォルト回答Noで回答すると、Error: Security Constraints Not Satisfied!エラーが出る。

samLambdaDebugPractice001 has no authentication. Is this okay? [y/N]

参考

SAMで環境ごとに異なるパラメータを設定してみた
AWS SAM でパラメータを扱う方法
SAM CLI を使ってできるだけローカルでテストしてからデプロイする

Discussion