Lambdaを使って開発してみたいなーと思ったときに、デバッグをローカルの環境でするのにdocker-lambdaが便利だったのでメモ。
はじめに
docker-lambdaとは?
A sandboxed local environment that replicates the live AWS Lambda environment almost identically – including installed software and libraries, file structure and permissions, environment variables, context objects and behaviors – even the user and running process are the same.
lambci/lambda – Docker Hub
ソフトウェアやライブラリ、ファイル構造などのAWS Lambbdaの環境をローカルで再現してくれるDocker image。追加したライブラリとかも含めて.zipにまとめて、本番環境にアップロードするファイルなんかも簡単につくれます。
環境
- Mac OS Catalina (10.15.4)
- Docker version (19.03.8)
- Python3.8 (の環境を試します)
Hello World!
適当なディレクトリを作成し、lambda_function.py
を作成
# lambda_function.py
def lambda_handler(event, context):
return "Hello docker lambda world!"
Dockerで実行
docker run --rm \
-v "$PWD":/var/task:ro,delegated \
lambci/lambda:python3.8 \
lambda_function.lambda_handler
# 出力
START RequestId: 9c...73 Version: $LATEST
END RequestId: 9c...73
REPORT RequestId: 9c...73 Init Duration: 621.98 ms Duration: 16.44 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 24 MB
"Hello docker lambda world!"
以上!一瞬で環境を構築して実行できました。
メモ
-v "$PWD":/var/task:ro,delegated
カレントディレクトリをマウント、lambda_function.pyをDocker内部から使えるようにしてる。lambci/lambda:python3.8
はDocker イメージの指定
lambci/lambda Tags – Docker Hub にあるタグを使って他の言語も対応
HTTPリクエストを受ける
docker run --rm \
-p 9001:9001 \
-e DOCKER_LAMBDA_WATCH=1 -e DOCKER_LAMBDA_STAY_OPEN=1 \
-v "$PWD":/var/task:ro,delegated \
lambci/lambda:python3.8 \
lambda_function.lambda_handler
Docker外部の新しいterminalから実行
curl -d '{}' http://localhost:9001/2015-03-31/functions/lambda/invocations
# 2015-03-31とは…? でもアクセスできる。。
# 出力
"Hello docker lambda world!"%
以上!!
メモ
- docker内部でエンドポイントが9001で立ち上がる。
-p 9001:9001
でローカルマシンからでも接続できるようにポートをつなげてる。 DOCKER_LAMBDA_STAY_OPEN=1
でURLによるアクセスができるようにするオプション。Dockerが起動したままになる。Ctrl+C
で終了。-v
でカレントディレクトリをマウントしているので、Dockerを止めずにプログラムを編集しても反映される。
ビルド方法
最終的に完成したプログラムは関連ファイルなど全部固めて.zip
に圧縮してAWS Lambdaにアップロードする。その.zip
ファイルを作る方法
必要なもの
- Dockerfile (ビルド用)
- requirements.txt (ライブラリ一覧)
Dockerfile
FROM lambci/lambda:build-python3.8
ENV LANG C.UTF-8
ENV AWS_DEFAULT_REGION ap-northeast-1
ADD . .
CMD pip install -r requirements.txt -t /var/task && \
zip -9 deploy_package.zip lambda_function.py && \
zip -r9 deploy_package.zip *
requirements.txt
必要なモジュールを書いていきます。改行区切りで書いていけばOK
(今回は必要ないけどrequestsモジュールを追加)
# requirements.txt
requests
ビルドするための環境構築
こちらはDockerfileに書いたとおりbuild-python3.8
というビルド用イメージが使われます。ビルド専用のDockerコンテナが作成されます。
# ビルドをするための環境構築
docker build -t build-image-python3.8 .
ビルド
実際のビルドは以下のコマンドです。依存関係のモジュールのインストールやらをやってくれます。docker build
は1回のみの実行で、以下のdocker run
だけビルドのたびに実行します。
# ビルド
docker run --rm -v "$PWD":/var/task build-image-python3.8
ビルドコマンドを実行すると依存関係で必要なモジュール類が全部カレントディレクトリに作成されます。今回だとrequestsのみをrequirements.txt
に書きましたが、certifiやchardetといった依存モジュールもインストールされています。
出力されたファイルのうちdeploy_package.zip
がライブラリも含めた圧縮ファイルで、これをアップロードすればLamda関数として利用することができる。
(ざっくり)Lambdaへのアップロード方法
AWS Lambda > 関数の作成 > 一から作成(適当に名前をつける & ランタイムをPython3.8に) > 関数の作成
関数の設定画面 Lambda > 関数 > (関数名) で 関数の設定画面より
関数コード > コードエントリタイプ=> .zipファイルをアップロード
より生成されたdeploy_package.zip
をアップロード。
実際にURLでアクセスする際にはAPI Gatewayの設定が少し必要。
ついでに、デフォルトの実行時間が3秒となっており、Lambdaから他のサイトの情報をとってきたりすると簡単に時間オーバーしてしまうので、関数の設定ページの下の方、[基本設定]のタイムアウトを少し長めにしておくといいかもです。
開発環境で外部パッケージをつかう
いろいろなサイトを調べていて、deploy_package.zip
にライブラリを追加する手順はわかりました。でも実際には手元でパッケージを含めて何度も試したものを最終的にdeploy_package
にまとめたいです。そんな時はどうするのか?
開発環境lambci/lambda:python3.8
を実行する際に、カレントディレクトリをマウントしていました。そこで、カレントディレクトリに必要なパッケージがインストールされていれば問題ないので、本番環境のビルド(lambci/lambda:build-python3.8
を使ったDockerfileのやつ)でビルド
(docker run --rm -v "$PWD":/var/task build-image-python3.8
)すると、必要なパッケージがカレントディレクトリにて構築されて、開発環境でも使えるようになります。
他にも、手元でpip install (パッケージ) -t ./
とかすれば行けそうですが、、このpipはローカル環境のpipなので、いい感じにbuild-python
の中でpip install
できたほうがいいと思います。
gspreadインストール時エラー
Google スプレッドシート(Google Sheets)をpythonから扱うライブラリgspread
をインストールしようとしたらエラーがでました。
ERROR: awscli 1.18.50 has requirement rsa<=3.5.0,>=3.1.2, but you'll have rsa 4.0 which is incompatible.
どうやらgspreadに依存してrsaのバージョン4.0がインストールされるが、awscli 1.18.50(すでに入ってる?)はrsaのバージョン3.1.2〜3.5.0が欲しいらしいです。エラーとか言いながらもきちんと出力できているのでヨシッとするか、requirements.txt
の最初にrsa == 3.4.2
とか書いておくと回避できます。(大丈夫なのか…?
まとめ
Lambdaの開発環境がとても簡単に構築でき、さらにビルドパッケージまで作成できました。むっちゃ便利!
余談ですがgspreadのProject descriptionが
“Super simple Google Spreadsheets Python API.”
とだけ書かれていました。全然詳細じゃないけどSuper simple descriptionだなと。実際gspreadは非常にシンプルで使いやすいのでオススメです!