AWS LambdaでDockerコンテナを動かす

こんばんは!DockerコンテナでごにょごにょしてLambda環境で実行させたいなぁと以前から思ってたので、今回やっと手を出してみました。
はじめに
当記事で解説する内容はほぼAWS公式の以下の内容となります。
https://docs.aws.amazon.com/lambda/latest/dg/images-create.html
やりたいこと
- AWS Lambda上でDockerコンテナ(Python)を実行したい
開発環境
Dockerエンジンは既にインストールされているものとします。
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
$ docker --version
Docker version 20.10.4, build d3cb89e
コンテナ内で実行するソースコード
今回は例として何の変哲もないHello, worldするだけのコードを実行させます。
注意すべき点は、ファイル名をapp.py、Lambda起動時に呼び出す対象となるメソッド名をhandlerと命名する必要があるところです。これを忘れるとハマります。
app.py
def handler(event, context):
print('hello, world')
return {
'isBase64Encoded': False,
'statusCode': 200,
'headers': {},
'body': 'ok'
}
Dockerfileを作成
次にAWSが配布しているpython用のコンテナをベースイメージに指定してDockerfileを作成します。
COPYでローカルのapp.pyをコンテナイメージ側にコピーしていますが、この時のイメージ側のパスは${LAMBDA_TASK_ROOT}(=/var/task)を指定する必要があります。
その次のCMDでは、app.pyのhandlerメソッドを呼び出すよう指定します。これも忘れるとソースコードが実行されませんので注意です。
FROM public.ecr.aws/lambda/python:3.9
# LAMBDA_TASK_ROOTはLambdaの環境変数で/var/taskを指す
COPY app.py ${LAMBDA_TASK_ROOT}
# Lambda起動時に実行するメソッドを指定
CMD ["app.handler"]
ECRにコンテナイメージをpushする
AWSコンソールからECRのリポジトリ一覧を開き、新規にリポジトリを作成した後、ローカルからECRへコンテナイメージをpushします。
pushまでのコマンドはリポジトリ画面の「プッシュコマンドの表示」を押せば、全て確認できるので指示に従ってpushしましょう。

Lambda関数を作成する
新規作成画面で「コンテナイメージ」を選択すると、コンテナイメージを入力する入力フォームが出てきますので、ECRにpushしたイメージを指定してLambdaを作成します。

テスト
準備が出来たのでちゃんと動作するかAWSコンソール上からLambdaのテストを実行します。

正常に動作していれば、テスト結果のログにhello, worldが出力されるはずです。
構築までにハマったこと
最初に作り出した時は、DockefileのCOPYで指定するコンテナ側のパスを${LAMBDA_TASK_ROOT}以外に指定していたり、ファイル名をapp.pyにしていなかったりしていた為、実行時にエラーが多発してなかなか苦戦しました。
最終的にAWS公式のドキュメントを見て解決し、ドキュメントの重要性を再確認しました。横着してはいかん…。