はじめに
過去の記事 その1で、Docker コンテナ内の Web アプリケーションを Window 環境の VSCode からデバッグできるようにしました。
また、過去の記事 その2では、テストレポートおよびカバレッジレポートを出力できる、自動ユニットテスト環境を構築しました。
しかし、2つの記事は Web アプリケーション内に構築する前提としてしまったために、やりたいことをピンポイントで伝える記事としてはイマイチ(?)だと思えてきました。
今回は、コンテナイメージを使用した AWS Lambda 関数(Python)の開発環境構築をする(自動ユニットテスト / デバッグモード)手順を、新しい記事として作り直すことにしました。
前提
過去の記事 その3の通りに、Windows に Docker の開発環境を構築する手順は実施済みの前提です。
今回のゴール
- 自動ユニットテスト
- Docker コンテナ内で起動している AWS Lambda 関数の自動ユニットテスト環境を構築する
- テストレポート(HTML形式/JUnit XML形式/Text形式)およびカバレッジレポート(HTML形式)を出力する
- デバッグモード
- Docker コンテナ内で起動している AWS Lambda 関数を VSCode からデバッグする
ディレクトリ構成
今回のディレクトリ構成は下記のようになります。
/home/appuser
├── workspace
│ ├── docker-compose.yaml
│ ├── .vscode
│ │ └── launch.json
│ └── lambda001
│ ├── Dockerfile
│ ├── opt
│ │ ├── bootstrap_debug
│ │ ├── lambda-entrypoint_debug.sh
│ │ └── pytest
│ │ ├── run_pytest.sh
│ │ └── reports
│ │ └ {yyyyMMddHHmmss}
│ └── var
│ └ task
│ ├ app.py
│ ├ pytest.ini
│ └ tests
│ └ test_app_001.py
手順
資材作成
自動ユニットテスト / デバッグモード 共通
-
docker-compose.yaml
ファイルを修正
docker-compose.yaml
ファイルを下記のように修正します。docker-compose.yamlversion: '3' services: ############################################################################## # Lambda container ############################################################################## lambda001: build: "./lambda001/" entrypoint: "/bin/bash" # Lambda アプリケーションが自動的に起動しないようにする設定 tty: true volumes: - "./lambda001/var/task/:/var/task/" # Lambda アプリケーションファイルの同期 - "./lambda001/opt/pytest/:/opt/pytest/" # pytest 関連ファイルの同期 ports: - "8080:8080" # Lambda port - "5678:5678" # Debug port image: "lambda001:develop" container_name: "lambda001"
-
Dockerfile
ファイルを作成
Dockerfile
ファイルを下記のように作成します。Dockerfile# Python 3.12.1 FROM public.ecr.aws/lambda/python:3.12.2024.03.04.10-x86_64 # Python のライブラリをインストール RUN pip3 install pytest==8.1.* RUN pip3 install pytest-cov==4.1.* RUN pip3 install pytest-html==4.1.* RUN pip3 install debugpy==1.8.* # 資材を配置する COPY ./var/task/ /var/task/ RUN mkdir -p /opt/pytest/reports/ COPY ./opt/pytest/ /opt/pytest/ COPY ./opt/bootstrap_debug /opt COPY ./opt/lambda-entrypoint_debug.sh/ /opt/ # パーミッションを変更する RUN chmod 755 /opt/bootstrap_debug RUN chmod 755 /opt/lambda-entrypoint_debug.sh # 起動時のコマンドを設定する CMD ["app.handler"]
-
Lambda ソースコードファイルを作成
Lambda ソースコードapp.py
ファイルを下記のように作成します。app.pyimport json def handler(event, context): param1 = event["param1"] if param1 == "param001": return { "statusCode": 200, "body": json.dumps("OK") } else: return { "statusCode": 500, "body": json.dumps("ERROR") }
自動ユニットテスト
-
テストコードファイルを作成
テストコードtest_app_001.py
ファイルを下記のように作成します。test_app_001.py# coding: UTF-8 import sys sys.path.append("/var/task/") import importlib import app as __app def test_app_001_xxxxx(): """ 自動テストのサンプル """ try: event = {"param1": "param001"} _app = importlib.reload(__app) res = _app.handler(event=event, context={}) assert res["statusCode"] == 200 except AssertionError as ae: raise ae except Exception as e: msg = str(e) assert False, f"Exception occurred. {msg}" def test_app_002_xxxxx(): """ 自動テストのサンプル """ try: event = {"param1": "param999"} _app = importlib.reload(__app) res = _app.handler(event=event, context={}) assert res["statusCode"] == 500 except AssertionError as ae: raise ae except Exception as e: msg = str(e) assert False, f"Exception occurred. {msg}"
-
pytest 設定ファイルを作成
pytest 設定ファイルpytest.ini
を下記のように作成します。pytest.ini[pytest] env = TZ=Asia/Tokyo AppEnv=TEST
-
テストレポートディレクトリを作成
権限を appuser にする都合上、テストレポートディレクトリを先に作成しておきます。WSL2 Ubuntumkdir -p /home/appuser/workspace/lambda001/opt/pytest/reports
-
pytest 起動シェルを作成
pytest 起動シェルrun_pytest.sh
を作成します。run_pytest.sh#!/bin/bash # pytest をカバレッジレポートを出力するモードで起動するシェルスクリプト datetime=$(date '+%Y%m%d%H%M%S') path=/opt/pytest/reports out_path=$path/$datetime mkdir -p $out_path/report_text/ mkdir -p $out_path/report_xml/ mkdir -p $out_path/report_html/ mkdir -p $out_path/coverage_html/ cd /var/task/ python -m pytest -c pytest.ini -s -v \ --junitxml=$out_path/report_xml/report.xml \ --html=$out_path/report_html/report.html \ --cov-report=html:$out_path/coverage_html/ \ --cov=/var/task/ \ --cov-branch /var/task/ > $out_path/report_text/report.txt
デバッグモード
-
デバッグモードで起動するシェルを作成
AWS Lambda 関数をデバッグモードで起動するために修正したシェルを2ファイル作成します。
5678 ポートでリッスンするようにしています。bootstrap_debug#!/bin/bash # AWS Lambda 関数をデバッグモードで起動するために修正したシェルスクリプト export AWS_EXECUTION_ENV=AWS_Lambda_python3.12 if [ -z "$AWS_LAMBDA_EXEC_WRAPPER" ]; then exec /var/lang/bin/python3.12 -m debugpy --listen 0.0.0.0:5678 /var/runtime/bootstrap.py else wrapper="$AWS_LAMBDA_EXEC_WRAPPER" if [ ! -f "$wrapper" ]; then echo "$wrapper: does not exist" exit 127 fi if [ ! -x "$wrapper" ]; then echo "$wrapper: is not an executable" exit 126 fi exec -- "$wrapper" /var/lang/bin/python3.12 -m debugpy --listen 0.0.0.0:5678 /var/runtime/bootstrap.py fi
lambda-entrypoint_debug.sh#!/bin/sh # AWS Lambda 関数をデバッグモードで起動するために修正したシェルスクリプト if [ $# -ne 1 ]; then echo "entrypoint requires the handler name to be the first argument" 1>&2 exit 142 fi export _HANDLER="$1" RUNTIME_ENTRYPOINT=/opt/bootstrap_debug if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then exec /usr/local/bin/aws-lambda-rie $RUNTIME_ENTRYPOINT else exec $RUNTIME_ENTRYPOINT fi
-
VSCode のデバッグ設定
launch.json
ファイルを作成
VSCode のデバッグ設定launch.json
ファイルを下記のように作成します。- コンテナ内とローカル環境のソースディレクトリをマッピング
- デバッグ連携用に5678番ポートを公開する
launch.json{ "version": "0.2.0", "configurations": [ { "name": "lambda001 Debugger", "type": "debugpy", "request": "attach", "connect": { "host": "localhost", "port": 5678 }, "pathMappings": [ { "localRoot": "${workspaceFolder}/lambda001/var/task", "remoteRoot": "/var/task" } ] } ] }
-
VSCode 設定
VSCode 設定は、過去の記事 その1の通りですので、こちらを参照してください。
動作確認
自動ユニットテスト / デバッグモード 共通
-
Docker Compose でビルド&起動
Docker Compose でカスタムイメージをビルドして起動します。WSL2 Ubuntucd /home/appuser/workspace docker-compose build docker-compose up -d
-
起動した Docker コンテナに入る
docker exec
コマンドで、起動した Docker コンテナに入ります。WSL2 Ubuntudocker exec -it lambda001 bash
自動ユニットテスト
-
pytest を起動する
シェルを実行して pytest を起動します。lambda001sh /opt/pytest/run_pytest.sh
-
テストレポートを確認する
Windows 環境から、出力されたテストレポートを確認します。
\\wsl$\Ubuntu-22.04\home\appuser\workspace\lambda001\opt\pytest\reports\{yyyyMMddHHmmss}
に下記のテストレポートが出力されています。
デバッグモード
-
AWS Lambda 関数をデバッグモードで起動
シェルを実行して、AWS Lambda 関数をデバッグモードで起動します。lambda001sh /opt/lambda-entrypoint_debug.sh app.handler
-
VSCode でデバッグ待機
VSCode の「実行とデバッグ(Ctrl+Shift+D)」タブから、lambda001 Debugger
を起動します。
また、app.py
にブレークポイントを設定します。
-
AWS Lambda 関数へリクエスト送信
AWS Lambda 関数へリクエスト送信します。
今回は、ローカル環境(Ubuntu)で、Curl コマンドを実行するものとします。WSL2 Ubuntucurl -X POST http://localhost:8080/2015-03-31/functions/function/invocations \ -H "Content-Type: application/json" \ -d '{"param1": "param001"}'
-
デバッグ操作を確認
ブレークポイントで処理が止まることを確認します。
また、ステップオーバー(F10)などの操作ができること、変数の値を参照できることを確認します。
最後に
今回は、今まで投稿してきたことの応用を、コンテナイメージを使用した AWS Lambda 関数の開発環境構築に適用してみました。
これで開発スピードをアップすることができるかと期待しています