🐳

Dockerを活用したLambdaの開発&本番環境のおすすめ構成

2024/05/26に公開

はじめに

Lambdaの開発&本番環境の構成について色々と試してきた結果、Dockerを利用するのが良かったのでオススメとして紹介します。
konan0802/lambda-docker-templateにソースコードを公開しているので、ぜひ試してみてください。

Lambda開発の一般的な課題

  • 開発環境の設定
    • 開発環境の構築時に本番環境との差異をなくす構成を取るのに苦労する
    • 環境の作り方によっては開発がしづらい構成になってしまう
  • 複数環境におけるデプロイ
    • DEV、STG、PRDなど環境が増えると、デプロイが複雑になる
    • 自動化すれば良いものの、複雑なものを自動化するのにも苦労する

よくある構成例と課題

1. エイリアスを使用した環境分割

Lambdaではエイリアス(prd、devなど)として環境を分けることができ、リリース時にはdevで検証し切ったものをバージョニングしてprdにアタッチするだけで本番リリースが行える。

  • 実装効率が悪い
    • 検証のたびにLambdaへデプロイしdevエイリアスで実行させる必要がある
  • エイリアス・バージョン管理が複雑
    • リリース時はコンソール操作だけで完結するが、逆に手作業が必要になるため、操作ミスのリスクがある。
    • リリース時に気をつけるLambdaの仕様(環境変数など)もいくつかあるため、それを把握していないことによるミスも生まれる。
    • 自動デプロイの設定も組めるが、その設定自体も複雑になる。

2. 関数ごとの分割

関数ごとに分離することで、エイリアス管理の複雑さを軽減し、操作ミスも防ぐことができる。

  • 実装効率が悪い(1と同じく)
    • 検証のたびにLambdaへのデプロイが必要

3. AWS SAMやServerless Frameworkの利用

開発環境構築やデプロイを自動化するためのツール。一度セットアップすれば、実装からリリースまでの効率を非常に高められる。

  • ツールのキャッチアップが必要
    • 自分だけが運用するのであれば何も問題ないが、チーム運用となるとチームメンバーのキャッチアップコストも気にかける必要があるため、チームメンバーの技術範囲も検討材料になる。
  • 権限譲渡(IAMなど)
    • 特にServerless Frameworkの構築時に思ったが、自動デプロイのためにIAMで相当の権限を渡す必要があり、権限の絞り込み設定の手間やセキュリティ的にも懸念を感じた。

Dockerを活用したLambdaの開発&本番環境のおすすめ構成

概要

LambdaではZIPファイルのデプロイに加えて、コンテナイメージを利用することもできる。そこでDockerを使えば開発環境の用意はもちろん、本番環境にもそのまま利用できるため、一貫性のある構成を作ることができる。

ディレクトリ構成

├── .env
├── Dockerfile
├── Dockerfile.dev
├── README.md
├── app
│   ├── __init__.py
│   ├── entrypoint.py
│   ├── lambda_function.py
│   ├── modules
│   │   ├── __init__.py
│   │   └── module_a.py
│   └── repositories
│       ├── __init__.py
│       └── sample_db.py
└── requirements.txt

コード例

Dockerfile

本番用イメージ。

Dockerfile
# AWS LambdaのPythonランタイムベースイメージを使用
FROM public.ecr.aws/lambda/python:3.12

# 必要なパッケージのインストール
COPY requirements.txt .
RUN python3.12 -m pip install -r requirements.txt

# Lambda関数のコードとモジュールをコンテナにコピー
COPY app ./

# Lambdaハンドラ関数の指定 (lambda_function.pyのlambda_handler関数を指定)
CMD ["lambda_function.lambda_handler"]

Dockerfile.dev

開発用イメージ。引数で擬似イベントを渡してテストできる。

Dockerfile.dev
# AWS LambdaのPythonランタイムベースイメージを使用
FROM public.ecr.aws/lambda/python:3.12

# 必要なパッケージのインストール
COPY requirements.txt .
RUN python3.12 -m pip install -r requirements.txt

# Lambda関数のコードとモジュールをコンテナにコピー
COPY app ./

# entrypoint.pyをエントリーポイントとして指定
ENTRYPOINT ["python", "entrypoint.py"]

entrypoint.py

ローカル開発のエントリーポイント。引数をJSONとしてLambda関数に渡す。

entrypoint.py
import sys
import json
from lambda_function import lambda_handler

def main():
    if len(sys.argv) > 1:
        try:
            event = json.loads(sys.argv[1])
        except json.JSONDecodeError:
            print("Invalid JSON input")
            return
        lambda_handler(event, None)
    else:
        lambda_handler(None, None)

if __name__ == "__main__":
    main()

lambda_function.py

Lambdaハンドラ本体。モジュールの呼び出しやDBモックとの連携を行います。

lambda_function.py
from modules import module_a
from repositories import sample_db


def lambda_handler(event, context):
    """
    サンプルLambdaハンドラ。
    module_aとsample_dbの両方を呼び出し、処理結果をまとめて返すだけ。
    """

    greeting = module_a.greet_user(event.get("name", "NoName"))
    db_response = sample_db.mock_db_access()

    print(
        {
            'StatusCode': 200,
            'Greeting': greeting,
            'DBResponse': db_response,
            'ReceivedEvent': event
        }
    )

    return {
        'StatusCode': 200,
        'Body': '正常に実行されました'
    }

実行方法(ローカル環境)

■ 環境

  • Docker

■ 実行方法

  1. 環境変数の設定
    .envをプロジェクトのルートディレクトリに作成する。
  2. Dockerイメージのビルド
    $ docker build -t docker-lambda-dev -f Dockerfile.dev .
    
  3. 実行
    $ docker run --rm docker-lambda-dev '{"name":"Alice"}'
    

本番環境

■ 環境

  • Lambda
  • ECR
  • 必要に応じてEventBridgeなど

■ デプロイ方法

  1. ECR
    [プッシュコマンドの表示]から手順通りにECRにイメージをプッシュ
  2. Lambda
    [新しいイメージをデプロイ]でECRにプッシュした最新のイメージを選択する

■ テスト方法

  • Lambdaのテストイベントから下記の形式で実行可能
    {
      "name": "Alice"
    }
    

利点

  • 実装効率
    • 開発時には下記のように3ステップがかかってしまうが、まぁそこまで負荷ではない
      1. イメージのビルド
      2. 実行
  • ツールのキャッチアップ
    • Dockerさえ使えれば何をしているかはコードに書かれているため、キャッチアップが容易
    • エンジニアはGUIでの操作より、コードを読んでコマンドを実行する方が手っ取り早い

まとめ

コンテナを用いて開発環境だけでなく本番環境まで運用している事例はあまり聞かないが、Lambda開発においてはLambdaがコンテナイメージを標準でサポートしているため、本番での環境構築も運用もスムーズに行えます。
より詳しいソースコードはkonan0802/lambda-docker-templateを参照して、ぜひ試してみてください。

Discussion