Docker × Python × AWS Lambdaで楽にWeb APIを建てるためのテンプレを作成しました。
普通にLambdaでAPIを建てるのとなにが違うの?
AWS Lambdaを使うとGUI上でサクッとWebAPIを建てることができて便利ですが、以下のような不便さもあります。
- Pythonのライブラリをインストールするのが面倒くさい。(ライブラリをインスールしたレイヤーを追加しなければならない。)
- ローカルでテストできない。(コードをアップデートするたびにデプロイし直さないといけない)
特に1つ目に関しては重要で、画像処理したいケースや機械学習のモデルを動かしたいケースなど、ライブラリが必要になるケースはかなり多いと思います。しかしLambdaで何らかのライブラリを使いたかったら、ライブラリをインスールしたのレイヤーをいちいち追加しなければいけません。しかもレイヤーを作る際はLambdaで使ってるPythonとバージョンを合わせないといけないのも地味に面倒です。
今回ご紹介する方法ですと、任意のライブラリをインストールしたWeb APIをサクッと建てることができます。しかもデプロイ前にローカルでAPIテストもできます。
テンプレート用意
テンプレートをGitHubに公開しています。
このテンプレを使って新しいリポジトリを作成し、お手元にgit clone
しておいてください。

1. セットアップ
1.1. AWS LambdaのRIEをダウンロードする
RIEとは「Runtime Interface Emulator」の略で、AWS Lambdaの環境をローカルでエミュレートするためのツールです。これを後で作るDockerイメージ内に組み込むことで、ローカルでLambdaのテストをできます。
リポジトリのルートに移動して以下のコマンドを実行してください。
curl -Lo aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie
chmod +x aws-lambda-rie
1.2. 必要なPythonライブラリを追加する
何か使いたいPythonライブラリがある場合は、”requirements.txt”にそのライブラリを追記してください。逆に追加のライブラリが必要ない場合このステップはスキップして構いません。
例えば画像処理ライブラリのPillowを使いたい場合は以下のように追記します。バージョンは適切なものを指定してください。
awslambdaric # ここは必須
Pillow==9.5.0 # ここ追加
1.3. DockerイメージをBuildする
以上の準備が整ったらDockerイメージを作成します。
docker build -t lambda-api .
以上でAPIのセットアップは完了です。
2. ローカルでテストする
作成したDockerイメージを使ってDockerコンテナを起動してみます。
docker run --rm -p 8000:8080 lambda-api:latest
すると、Web APIがlocalhost:8000/2015-03-31/functions/function/invocations でアクティブになりますので、ここにPOSTリクエストを送れば期待通りのレスポンスが返ってくるはずです。
試しにリクエクトを送ってみたい場合は以下を実行してみてください。
curl -X POST -H "Content-Type: application/json" -d '{}' localhost:8000/2015-03-31/functions/function/invocations
{"message": "Hello World"}
と表示されればOKです。
3. 作成したイメージをECRへアップロードする
ステップ1.3.で作成したイメージをAWSのECR(AWSが提供するDockerイメージ管理サービス)へアップロードしていきます。
ここからは前提としてAWS CLIを使用できるようにしておいてください。
3.1. 環境変数設定
まず以下のように3つの環境変数を設定しておきます。
REGION="ap-northeast-1"
ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
ECR_REPO_NAME="lambda-api"
REGION
とECR_REPO_NAME
は任意の値に変えてもらって構いません。
3.2. ECRにログイン
aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com
Login Succeeded
と表示されればOKです。
3.3. ECRのリポジトリを作成する
aws ecr create-repository --repository-name $ECR_REPO_NAME
このコマンドでECRのリポジトリを作成します。(この時点ではまだ中身は空)
ちなみにこのコマンドはリポジトリの枠を作成するだけのコマンドなので、初回だけ実行します。後でイメージを上げ直したい場合などがあっても2回目を実行する必要はありません。
3.4. イメージにDockerタグをつける
ステップ1.3.で作成したイメージに、ECR用のDockerタグをつけます。
docker tag lambda-api:latest ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${ECR_REPO_NAME}:latest
これでECRにpushする準備は完了です。
3.5. イメージをECRにpushする
docker push ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${ECR_REPO_NAME}:latest
これでpush完了です。
ブラウザでAWSのECRにアクセスしてみると、無事イメージが上がっていることが確認できますね。

4. AWS Lambda作成
ここからはGUI上でのポチポチ操作になります。
ブラウザ上でAWS Lambdaにアクセスして、「関数の作成」をクリックします。
※イメージをpushしたECRと同じリージョンにいる必要があることを注意してください。
そしてステップ3.5.で追加したイメージを元にLambda関数を作成します。

イメージのアーキテクチャがわからない場合は、以下のコマンドで確認してください。
docker image inspect lambda-api:latest | grep Architecture
amd64
と出た場合はx86_64
と同義です。
5. API Gatewayと繋げる
ここまでだとまだLambda関数を作成しただけで、Web APIとして呼び出すことはできません。
AWSのAPI Gatewayという機能を使って、このLambda関数をWeb APIとして呼び出せるようにしていきます。
5.1. APIを作成する
API Gatewayのページにアクセスし、「APIを作成」をクリックします。
APIのタイプを訊かれるので、「REST API」を選択して、適当なAPI名でAPIを作成します。
5.2. メゾットを作成する
ステップ5.1.で作成したAPIの設定ページで、「メゾットを作成」をクリックします。
そして以下のように設定を行います。

選択するLambda関数はステップ4.で作成したものを選択してください。
5.3. APIをデプロイする
作成したAPIの設定ページで、「APIをデプロイ」をクリックします。
ここでは「ステージ」と呼ばれるものの名前を入力します。「ステージ」はAPIのバージョン管理のようなもので、テスト用や本番用などの環境を分けることができます。
今回は「test」など適当なステージ名をつけておきます。

これでAPIを呼び出せるようになりました。
5.3. APIをテストする
最後にデプロイされたAPIをテストしてみましょう。
デプロイした「ステージの詳細」から、Web APIのURLを確認できます。

このURLに対してPOSTリクエストを送ってみて、期待通りのレスポンスが返って来れば成功です!
curl -X POST -H "Content-Type: application/json" -d '{}' https://xxx.ap-northeast-1.amazonaws.com/test
6. 実装変更と再デプロイ
最後に、APIの実装の変更方法と、再デプロイの手順を簡単に説明しておきます。
6.1. APIの実装を変更する
テンプレートのままだと、このAPIは”Hello World”と書かれたシンプルなJSONを返すような処理になっています。このAPIのメイン処理は”app.py”に記述されており、この中身は自由に変更して大丈夫です。
なお、リクエストBodyはevent
パラメータそのものとして受け取ることができますので、必要な場合はそれを参照してください。
6.2. APIを再デプロイする
実装を変更してそれを反映させるためには、Lambdaが参照しているイメージを更新すれば良いだけです。
まず「ステップ1.3.」「ステップ3.4.」「ステップ3.5.」のみを再度実行して新しいイメージを再pushします。
その後、Lambdaの設定画面で「新しいイメージをデプロイ」を選択して、最新のイメージを再選択すれば完了です。

お疲れ様でした!
コメント