🐳
cdk でデプロイ可能な uv 管理の AWS Lambda コンテナイメージのスケルトン
普段、pythonで書いたLambdaをStepfunctionsなどにして、cdkでIaCすることで楽に色々な仕組みを作っています。特にLambdaは、コンテナイメージとして開発することで、関数1つあたりのパッケージサイズや、アカウント全体のアーカイブやレイヤーサイズの総計に関するクォータの低さに縛られない開発ができますし、ECSなどへの転用もしやすくなります。
また、python言語は使える人が多い一方で、パッケージやプロジェクト管理ツールがいくつもあるので色々なスタイルがあってメンバー間でツールの統一に少し困ります。あまり古いものをずっと使っていると、他のメンバーの足を引っ張ってしまいます。
などなど諸般の理由から、新し目で流行りそうなuvとコンテナ技術を使ったリソースをCDKでIaCしながらデプロイすることができれば、しばらくは使えそうなので試してみました。
前提
uv, docker engine, npm をインストール済の状態とします。OS は Ubuntu 24 LTS の想定です。
ランタイムやエンジンまわりを準備します。cdk の python のサンプルコードをベースにします。
bash ~/${workspaceFolder}
$ uv python install 3.12
$ npm install -g aws-cdk
$ cdk init app --language python
$ uv init
$ uv add -r requirements.txt && rm -f ./requirements.txt
$ uv add -r requirements-dev.txt --dev && rm -f ./requirements-dev.txt
$ mkdir -p ./src
$ touch ./src/sample_lambda.py ./Dockerfile
コードとIaCを書く
Dockerfile
を書きます。
${workspaceFolder}/Dockerfile
# AWS Lambda 関数の公式コンテナイメージ https://gallery.ecr.aws/lambda/python で
# uv https://docs.astral.sh/uv/ を使って python パッケージ管理と実行を可能にする最小限の例
FROM public.ecr.aws/lambda/python:3.12
# uv を公式イメージからCOPYする方法でインストールする
# https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
COPY /uv /bin/uv
ENV PATH="/app/.venv/bin:$PATH"
# AWS Lambda は書込可能なディレクトリが `/tmp` 配下だけなので uv の cache も同ディレクトリ配下を使うように変更する
# https://docs.astral.sh/uv/configuration/environment/
ENV UV_CACHE_DIR=/tmp/.uv_cache
# uv の lockfile からプロジェクトの python パッケージ をインストールする
COPY pyproject.toml uv.lock ${LAMBDA_TASK_ROOT}/
RUN uv sync
# Lambda関数のコード `./src/` をイメージに含める
COPY src/ ${LAMBDA_TASK_ROOT}/
# AWS Lambda イメージのデフォルトのエントリーポイント `lambda-entrypoint.sh` を
# uv の仮想環境で実行させることで sync したパッケージが利用可能なコンテキストでLambdaを実行させる
ENTRYPOINT ["uv", "run", "/lambda-entrypoint.sh"]
# `lambda-entrypoint.sh` に `./src/lambda_handler.py` の `handler(event, context)` を
# Lambda関数のエントリーポイントとして指定する例。プロジェクトに合わせてお好みで
# CMD ["lambda_handler.handler"]
Lambda のコードを書きます。
${workspaceFolder}/src/sample_lambda.py
def handler(event, context):
return {'statusCode': 200, 'body': 'Hello from Lambda!'}
cdk スタックを書きます。コンテナイメージとしてビルドされる Lambda 関数で、ハンドラは先のコードを使う構成です。イメージは ECR に push されます。
${workspaceFolder}/temp/temp_stack.py
from aws_cdk import aws_lambda
from aws_cdk import Duration, Stack
from constructs import Construct
class TempStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
code = aws_lambda.DockerImageCode.from_image_asset(directory=".", cmd=["sample_lambda.handler"])
aws_lambda.DockerImageFunction(scope=self, id=f"sample-lambda" code=code)
デプロイする
bash ~/${workspaceFolder}
$ npx cdk bootstrap
$ npx cdk deploy
Lambda関数が1つデプロイできたら成功です。テスト実行すると HTTP 200 Hello from Lambda!
を返してくれるはずです。
Discussion