0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コンテナイメージを使用した AWS Lambda 関数の開発環境構築をする(自動ユニットテスト / デバッグモード)

Posted at

はじめに

過去の記事 その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 からデバッグする

ディレクトリ構成

今回のディレクトリ構成は下記のようになります。

WSL2 Ubuntu
/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

手順

資材作成

自動ユニットテスト / デバッグモード 共通

  1. docker-compose.yamlファイルを修正
    docker-compose.yamlファイルを下記のように修正します。

    docker-compose.yaml
    version: '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"
    

  2. 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"]
    

  3. Lambda ソースコードファイルを作成
    Lambda ソースコードapp.pyファイルを下記のように作成します。

    app.py
    import 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")
            }
    

自動ユニットテスト

  1. テストコードファイルを作成
    テストコード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}"
    

  2. pytest 設定ファイルを作成
    pytest 設定ファイルpytest.iniを下記のように作成します。

    pytest.ini
    [pytest]
    env =
        TZ=Asia/Tokyo
        AppEnv=TEST
    

  3. テストレポートディレクトリを作成
    権限を appuser にする都合上、テストレポートディレクトリを先に作成しておきます。

    WSL2 Ubuntu
    mkdir -p /home/appuser/workspace/lambda001/opt/pytest/reports
    

  4. 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
    

デバッグモード

  1. デバッグモードで起動するシェルを作成
    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
    

  2. 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"
                    }
                ]
            }
        ]
    }
    

  3. VSCode 設定
    VSCode 設定は、過去の記事 その1の通りですので、こちらを参照してください。

動作確認

自動ユニットテスト / デバッグモード 共通

  1. Docker Compose でビルド&起動
    Docker Compose でカスタムイメージをビルドして起動します。

    WSL2 Ubuntu
    cd /home/appuser/workspace
    docker-compose build
    docker-compose up -d
    

  2. 起動した Docker コンテナに入る
    docker execコマンドで、起動した Docker コンテナに入ります。

    WSL2 Ubuntu
    docker exec -it lambda001 bash
    

自動ユニットテスト

  1. pytest を起動する
    シェルを実行して pytest を起動します。

    lambda001
    sh /opt/pytest/run_pytest.sh
    

  2. テストレポートを確認する
    Windows 環境から、出力されたテストレポートを確認します。
    \\wsl$\Ubuntu-22.04\home\appuser\workspace\lambda001\opt\pytest\reports\{yyyyMMddHHmmss}に下記のテストレポートが出力されています。

    • カバレッジレポート(HTML形式):coverage_html\index.html
      スクリーンショット.png
    • テストレポート(HTML形式):report_html\report.html
      スクリーンショット.png
    • テストレポート(JUnit XML形式):report_xml\report.xml
    • テストレポート(Text形式)(デフォルト):report_text\report.txt

デバッグモード

  1. AWS Lambda 関数をデバッグモードで起動
    シェルを実行して、AWS Lambda 関数をデバッグモードで起動します。

    lambda001
    sh /opt/lambda-entrypoint_debug.sh app.handler
    

  2. VSCode でデバッグ待機
    VSCode の「実行とデバッグ(Ctrl+Shift+D)」タブから、lambda001 Debuggerを起動します。
    また、app.pyにブレークポイントを設定します。
    スクリーンショット 2025-02-11 133517.png

  3. AWS Lambda 関数へリクエスト送信
    AWS Lambda 関数へリクエスト送信します。
    今回は、ローカル環境(Ubuntu)で、Curl コマンドを実行するものとします。

    WSL2 Ubuntu
    curl -X POST http://localhost:8080/2015-03-31/functions/function/invocations \
     -H "Content-Type: application/json" \
     -d '{"param1": "param001"}'
    

  4. デバッグ操作を確認
    ブレークポイントで処理が止まることを確認します。
    また、ステップオーバー(F10)などの操作ができること、変数の値を参照できることを確認します。
    スクリーンショット 2025-02-11 133517.png
    ddd.png

最後に

今回は、今まで投稿してきたことの応用を、コンテナイメージを使用した AWS Lambda 関数の開発環境構築に適用してみました。
これで開発スピードをアップすることができるかと期待しています

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?