内容
CDKで実装した Python Lambda のローカルデバッグ環境構築する
Lambdaの実行環境と合わせるため、Lambdaと同環境のコンテナを用意し、
Remote Developmentでコンテナに入りデバッグを行う
本記事で一旦ここまでを実施する
以下は別記事で対応する
フォルダ構成
今回以下のようにLambdaごとに外部パッケージをインストールしているが、
Lambdaのサイズ上限も考慮すると、EFS上に外部パッケージをインストールしてLambdaにアタッチする(参考)ほうが良さそうなため、
後日試してみる予定
→ AWS CDK - EFS での Python Lambda パッケージ管理
├─ .devcontainer
│ └─ devcontainer.json
├─ .vscode
│ ├─ extensions.json
│ └─ settings.json
│
├─ bin/
│ └─ sample.ts
│
├─ lib/
│ │
│ ├─ handlers/ // Lambda実装
│ │ │
│ │ └─ sample-function/
│ │ ├─ python/
│ │ │ ├─ pandas/ // 外部パッケージ
│ │ │ …
│ │ │ └─ sample_function.py // Lambda関数実装
│ │ │
│ │ └─ requirements.txt // Lambdaに含める外部パッケージ指定
│ │
│ ├─ layers/ // Layer実装
│ │ │
│ │ ├─ python/
│ │ │ ├─ pytz/ // 外部パッケージ
│ │ │ …
│ │ │ └─ common_layer.py // layerに含める共通処理実装
│ │ │
│ │ └─ requirements.txt // layerに含める外部パッケージ指定
│ │
│ └─ sample-stack.ts
│
├─ test/
│ │
│ ├─ sample-function/
│ │ └─ test.py // lib/handlers/sample-function/python/sample_function.pyのテストコード
│ │
│ ├─ docker-compose.yml
│ └─ Dockerfile-lambda-python // Python Lambda実行用のコンテナDockerfile
…
│
├─ poetry.lock
├─ pyproject.toml
│
テスト対象Lambda関数コード
import os
from datetime import datetime
from pytz import timezone
from common_layer import print_message # type: ignore | common layer package
import pandas as pd
test_env_value = os.getenv("TEST_ENV_VALUE")
def handler(event, context):
print(f"event: {event}") # イベント内容の確認
print(f"test_env_value: {test_env_value}") # 環境変数の確認
print_message("test message 1") # Layerを使った処理
df = pd.DataFrame([["A", 170, 60], ["B", 160, 50], ["C", 165, 58]]) # 外部パッケージpandasを使った処理
print(f"df: {df}")
tokyo_dt = datetime.now(timezone("Asia/Tokyo"))
return {"statusCode": 200, "body": tokyo_dt.strftime("%Y-%m-%d %H:%M:%S")}
テストコード
import os
from common_layer import print_message
os.environ["TEST_ENV_VALUE"] = "test env value" # 環境変数設定
import sample_function
def test_1():
print_message("layer test")
event = {"key1": "value1", "key2": "value2"} # Lambda handlerの引数設定
context = {}
sample_function.handler(event, context) # Lambda handlerの実行
test_1()
import パスの追加
テストコード test/sample-function/test.py
から、
layer内の外部パッケージ + 共通処理、
Lambda内の外部パッケージ、handlerが実行できるように
pyproject.toml内 [tool.poetry]
ブロックの packages
でimportパスを追加する
(sys.path.append("<path>")
でimportパスを追加するのと同じ)
[tool.poetry]
name = "sample"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
readme = "README.md"
packages = [
{ from = "lib/layers/python", include = "*" },
{ from = "lib/handlers/sample-function/python", include = "*" },
]
[tool.poetry.dependencies]
python = "3.11.6"
boto3 = "^1.28.78"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Lambdaと同環境のimageにboto3はインストールされているが、
poetryのinterpreterを使用するため、boto3は必要
Python Lambda 実行用のコンテナ
Python11のLambdaイメージをベースに、必要なモジュールをインストールする
FROM public.ecr.aws/lambda/python:3.11
RUN yum update -y
RUN yum install -y unzip tar gzip less
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && unzip awscliv2.zip && ./aws/install
RUN pip install poetry
CMD ["/bin/bash"]
docker-compose
ソースコード一式をコンテナ内の /lambda-python
に同期する
クレデンシャルも同期する
version: "3.8"
services:
lambda:
container_name: lambda-python
build:
context: .
dockerfile: Dockerfile-lambda-python
volumes:
- ../:/lambda-python
- ~/.aws:/root/.aws
working_dir: /lambda-python
Remote Development でのデバッグ
以下のように .devcontainer/devcontainer.json
を設定しているが必須ではない
{
"name": "lambda-python",
"dockerComposeFile": ["test/docker-compose.yml"],
"service": "lambda",
"workspaceFolder": "/lambda-python"
}
コンテナ起動後、 Remote Development
を使用してPython Lambda実行用のコンテナにアタッチする
Open Folderからソースコード一式を同期した lambda-python
フォルダを開く
poetry install
実行後、poetryのinterpreterを選択する
Layer、Lambdaに含める外部パッケージは以下コマンドでpythonフォルダ以下にインストールする
pip install -r requirements.txt -t python/
Pythonデバッグに必要な拡張機能 ms-python.python
をインストールする
test/sample-function/test.py
を開いてデバッグ実行を行う
AWSサービス(S3)をLocalStackでモック化
Python Lambda - コンテナ上でのローカルデバッグ環境構築(AWSサービス(S3)のモック化)