AWS Lambda の Container Runtime を GitHub Actions で E2E テストしたい時の備忘録
AWS Lambda の Container Runtime を GitHub Actions で E2E テストしたい時の備忘録
はじめに
機械学習のAPI提供として AWS Lambda の Container Runtime を使うことがよくあります。
pytest などを用いて開発環境で unit test はよく行いますが、さらにDocker Container としての成果物の E2E テストをすることでより安全性を高めることができます。
今回はこの E2E テストを GitHub Acitons 上で行うための備忘録です。
ほとんどの内容は以下のブログ記事を参考にしてます。(ありがとうございます 🙇 )
差分はpythonでテストを書いてることくらいだと思われます。
なので、詳細は引用してるブログ記事を参照してください。
想定読者
- AWS LambdaのコンテナをGHA上でE2Eテストしたい未来の自分
GitHub ActionsでのTest Job
GtiHub ACtions上でのテストのワークフローの定義は以下のようになります。
name: test
on: push
jobs:
test:
name: Run E2E Test on Docker Containers
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run E2E Test on Docker Containers through Docker Network
run: docker compose up server -d && docker compose up test
ポイントは、AWS Lambda Container を docker compose up server -d
で推論サーバーとしてバックプロセスで立ち上げてからテスト用のコンテナを立ち上げてるところです。
こうしないとうまく動きません。step 間では環境が分かれてるので、同一ステップ内でテストしたい推論サーバーを立てて、別のテスト用のコンテナを立ててテストしています。
pytest なら E2E 用のマーカーをテストにつけておくみたいな工夫もあってもいいかもしれません。
特別なことはしてませんが、機械学習の E2E テストはモデルのロードや推論など重めの処理が乗ることが多いので、develop ブランチに pushした時のみトリガーされるような設定を付け足しておくといいと思います
name: test
on: push
jobs:
test:
name: Run E2E Test on Docker Containers
runs-on: ubuntu-latest
# develop/mainブランチにpushした時のみトリガー
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Run E2E Test on Docker Containers through Docker Network
run: docker compose up server -d && docker compose up test
各 Dockerfile と AWS Lambda のサンプルコード
推論用の Dockerfile
推論サーバーとしての Dockerfile は以下のようになります。
python の環境構築に rye を使ってるので rye で生成された lock ファイルを使って、LAMBDA_TASK_ROOT に必要なパッケージをインストールします。
FROM public.ecr.aws/lambda/python:3.10 as app
WORKDIR ${LAMBDA_TASK_ROOT}
# README.md,pyproject.tomlがないとinstall時にコケる
COPY README.md pyproject.toml requirements.lock "${LAMBDA_TASK_ROOT}"
RUN \
python -m pip install --upgrade \
'pip==24.2' \
'wheel==0.43.0' \
'setuptools==72.1.0' && \
python -m pip install --no-cache-dir -r requirements.lock -t "${LAMBDA_TASK_ROOT}"
COPY . "${LAMBDA_TASK_ROOT}"
CMD [ "src.example_aws_lambda_e2e_test_on_gha.app.handler" ]
E2E テスト用の Dockerfile
E2E テスト用の Dockerfile は以下のようになります。
FROM python:3.10 AS builder
ENV ORIGIN=http://localhost:8080
WORKDIR /app
COPY . .
RUN \
python -m pip install --upgrade \
'pip==24.2' \
'wheel==0.43.0' \
'setuptools==72.1.0' && \
pip install -r requirements.lock && \
pip install -r requirements-dev.lock
CMD ["pytest"]
推論用コードとその E2E テストコード
推論用の lambda function のコードは今回何でもいいのでリクエストが来たら、 message
キーできたものを返すだけの簡単なものにしてます。
from enum import Enum
from aws_lambda_powertools.utilities.typing import LambdaContext
class Status(Enum):
OK = 200
BAD_REQUEST = 400
FORBIDDEN = 403
NOT_FOUND = 404
INTERNAL_SERVER_ERROR = 500
def handler(event: dict, _: LambdaContext) -> dict:
msg = event.get("message")
status = Status.OK
if msg is None:
msg = "Not Found"
status = Status.BAD_REQUEST
return {"message": msg, "status": status.value}
E2E テスト用のコードでは、推論サーバーにDocker Network 経由でリクエストを投げるようにします
import os
import json
import requests
import pytest
ORIGIN = os.getenv("ORIGIN", "http://localhost:8080")
@pytest.fixture
def sample_success_request() -> str:
return json.dumps({"message": "Hello, World!"})
def test_app_should_success(sample_success_request: str) -> None:
response = requests.get(
f"{ORIGIN}/2015-03-31/functions/function/invocations",
data=sample_success_request,
)
assert getattr(response, "status_code") == 200, (
f"Requested to {ORIGIN}. Expected status code 200, but got {response.status_code} "
+ "You should check the environment variable ORIGIN in compose.yaml. "
+ "If you are on GitHub Action, please check 'http://server:8080' is allowed. "
)
response_json = response.json()
assert response_json.get("message") == "Hello, World!", (
f"Requested to {ORIGIN}. Expected message 'Hello, World!', but got {response_json.get('message')} "
+ f"RESPONSE_JSON: {response_json}"
)
以上のコードを組み合わせて、GitHub Actions 上で E2E テストを行うことができます。
コードはこのリポジトリで公開しています。
まとめ
- AWS Lambda の Container Runtime を使った E2E テストを GitHub Actions 上で行う方法についてまとめました
- Docker Network を使って推論サーバーを立ててからテスト用のコンテナを立てることで E2E テストを行うことができます
Discussion