LoginSignup
0
1

More than 1 year has passed since last update.

SAMでAWS Lambda(カスタムイメージ) + API Gatewayを構成するときに、できるだけ効率的なlambda関数のunit testを考える

Posted at

概要

Lambda + API GatewayをSAMを使って構成するときに、カスタムイメージを使ったlambda関数に関する情報があまり出て来なかったので、試行錯誤した内容を残す。具体的には以下の内容。

  • lambda関数をカスタムイメージで作るときに、作った関数をunit testするときのtips

カスタムイメージを使ってlambda関数をunit testすることの難しさ

カスタムイメージを前提としたLambda + APIGatewayを構成しようとすると、大体以下のようなディレクトリ構成になる。

.
├── README.md
├── __init__.py
├── lambda_function
│   ├── Dockerfile
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── events
│   └── event.json
├── samconfig.toml
├── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py

一方、lambda関数を動かすカスタムイメージとして、公式では以下のようなDockerfileを例示している。

# Define function directory
ARG FUNCTION_DIR="/function"

FROM python:buster as build-image

# Install aws-lambda-cpp build dependencies
RUN apt-get update && \
  apt-get install -y \
  g++ \
  make \
  cmake \
  unzip \
  libcurl4-openssl-dev

# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}

# Copy function code
COPY app/* ${FUNCTION_DIR}

# Install the runtime interface client
RUN pip install \
        --target ${FUNCTION_DIR} \
        awslambdaric

# Multi-stage build: grab a fresh copy of the base image
FROM python:buster

# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}

# Copy in the build image dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}

ENTRYPOINT [ "/usr/local/bin/python", "-m", "awslambdaric" ]
CMD [ "app.handler" ]

要は以下の感じ。

  • 特定のディレクトリ(FUNCTION_DIR)にpythonのresourceを一通りpip install
  • multi-stage buildでまっさらな環境にコピーして、lambda関数の実行環境・コマンド等を整備

ただ、この通り作ると、以下の観点でlambda関数のunit testがやりづらくなる。

  • ローカル(imageの外)でのテストがやりづらい
    • 処理がpythonで完結しない(python以外のモジュールを呼び出してる、など)場合は、それらをローカルにインストールする必要があるが、unit testのためだけにそれする?
  • buildしたimageを使っても、微妙にテストしづらい
    • テストを実行するにあたって、ENTRYPOINTが微妙に邪魔

multi-stage buildで生成される中間imageを利用する

ところで先ほどのDockerfileの例を見ると、multi-stage buildが利用されている。

multi-stage buildを使うと、最終的に生成されるimage以外に中間stageも生成される(以下の<none>ってやつ)。これを使えば良いのでは?というのが、今回のコンセプト。

REPOSITORY        TAG            IMAGE ID       CREATED          SIZE
lambda-function   latest         77fa66e7adc8   12 minutes ago   3.37GB
<none>            <none>         70dd38f37db9   12 minutes ago   4.29GB

具体的には、FUNCTION_DIRにテストに必要な資材をmountし、<none>のイメージを使ってテストを実施する、という感じ。

docker run --rm
  --mount type=bind,src="$PWD/lambda_function",dst="$FUNCTION_DIR/lambda_function"
  --mount type=bind,src="$PWD/tests",dst="$FUNCTION_DIR/tests"
  -w $FUNCTION_DIR
  $(docker images -f "dangling=true" -q)
  /bin/bash -c "pip install pytest pytest-mock mocker && python -m pytest tests"

終わりに

なんかもっといい方法ありそうなんだよなぁ、、、

0
1
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
1