コンテナ Lambda お手軽環境構築
AWSベースイメージを使ったコンテナLambdaはチュートリアルがあります(例: Node.js, Python)。
この手順通りに進めると確かにローカル開発できるのですが、ソースコードの変更ごとにdocker build
が発生するので非常に面倒です。
そこで、チュートリアルのDockerfileは変えずに、docker run
のオプションを駆使してローカル開発をしてみました。
※以下ではPythonのベースイメージを使用しています。
準備
まず以下のようなファイル構成にします。
sample_function
├── Dockerfile
├── lambda_function.py
└── requirements.txt
Dockerfile
は以下のようになります(公式の通りです)。
FROM public.ecr.aws/lambda/python:3.12
# Copy requirements.txt
COPY requirements.txt ${LAMBDA_TASK_ROOT}
# Install the specified packages
RUN pip install -r requirements.txt
# Copy function code
COPY lambda_function.py ${LAMBDA_TASK_ROOT}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "lambda_function.handler" ]
lambda_function.py
は単純なprint
とreturn
だけにしました(ここは任意です)。
def handler(event, context):
print("Hello, world!")
return "ok"
ここではまだライブラリを使用しないのでrequirements.txt
は空で良いです。
ビルド
sample_function
ディレクトリに入って以下のコマンドを実行します。
docker build --platform linux/amd64 -t sample_function .
手元の環境ではM1 Mac (arm64) で実行しているので--platform
が入っています。
実行
以下の通りdocker run
で実行します。ここで該当のスクリプトをマウントするようにしています。
docker run --rm --platform linux/amd64 -v $(pwd)/lambda_function.py:/var/task/lambda_function.py -p 9000:8080 sample_function lambda_function.handler
また、Lambdaへのリクエストはこのようになります。
curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
以下は実行結果のスクリーンショットです(左: docker run、右: curl)。
ただし、ホットリロードのような機能は無いので、ソースコードを変更するたびにdocker run
し直す必要があります。
参考: ホットリロードを実装してみた
※ここからは実験的なものなので、あまり実用的では無いかもしれません。
以下は1秒ごとにソースコードの変更を検知し、コンテナを起動し直すbashスクリプトです。
#!/bin/bash
COMMAND="docker run -d --rm --platform linux/amd64 -v $(pwd)/lambda_function.py:/var/task/lambda_function.py -p 9000:8080 sample_function lambda_function.handler"
# 監視するファイルのパス
FILE_TO_WATCH="./lambda_function.py"
# 初期タイムスタンプを取得
initial_timestamp=$(stat -f "%a" "$FILE_TO_WATCH")
# コンテナを起動し、コンテナIDを取得
container_id=$($COMMAND)
log() {
docker logs -f $container_id &> ./logs.txt &
}
log
# コンテナを削除する関数
cleaning() {
docker kill $container_id > /dev/null
}
# 終了時にコンテナを削除
trap cleaning EXIT
# 無限ループでファイルの変更を監視
while true; do
# 現在のタイムスタンプを取得
current_timestamp=$(stat -f "%a" "$FILE_TO_WATCH")
# タイムスタンプが変更された場合
if [ "$current_timestamp" -ne "$initial_timestamp" ]; then
echo "File has been modified."
cleaning
container_id=$($COMMAND)
log
# タイムスタンプを更新
initial_timestamp=$current_timestamp
fi
# 次のチェックまで待機
sleep 1
done
このときログはlogs.txt
に出力されるので、tail -f logs.txt
などで確認することができます。