💭

localstack×terraformでlayer付きlambdaをローカルデプロイ

に公開

本記事では、localstackとterraformを組み合わせて、layerありのlambda関数をローカル環境で効率的にデプロイする方法を解説します。
実際のコードやディレクトリ構成、ハマりどころも紹介します。

結論

コードを見るのが一番わかり易いと思うので、こちら!

はじめに

従来、localstackの初期化処理でbashスクリプトを用いてS3やLambdaなどのリソースを手動で作成していました(/etc/localstack/init/ready.d配下でawslocalコマンドを実行)。
しかし、localstackの無料版ではlambda layerが使えないという制約があり、独自実装が必要でした。

この方法には以下の課題がありました。

  1. 実装が複雑
    命令的なスクリプトとなり、リソース作成順序の管理やエラー対応が煩雑でした。
  2. キャッシュが効かない
    dockerのキャッシュが効かず、初期化のたびに数分かかることもありました。

解決策:terraformによる宣言的な環境構築

これらの課題を解決するため、terraformを用いてリソースを宣言的に管理する方法に切り替えました。(s3も同時に作成したかったため、samではなくterraformを選択)

システム構成図

下図は、lambdaのビルドとデプロイで別々のコンテナを立てている構成です。
一見複雑になった様に見えますが、従来の手動実装と比べてリソース定義がシンプルになり、ビルドとデプロイの責務分離で見通しも良くなりました。
lambdaのビルドは独立しているので、動作確認もしやすいです。[1]

変更前

before

変更後

after

参考リポジトリ

今回の実装の全コードは以下のブランチにあります。

ディレクトリ構成と各役割

以下のような構成になっています。

  • lambda_builderでlambdaのコードをビルド、zip化します。
  • terraformでzip化したファイルを参照し、lambdaを定義します。
  • docker-compose.ymlでディレクトリの共有やビルド設定コマンドの設定をします。
.
├── README.md
├── docker-compose.yml ... 全体の設定
├── lambda_builder
│   ├── Dockerfile ... lambda をビルドするDockerの設定。lambda.tfで指定するpythonのバージョンと合わせる
│   └── Makefile ... ビルド時に使うpythonのインストールやrequirements.txtを使った必要なライブラリのインストールをする
├── src
│   ├── index.py ... lambdaの実装
│   └── requirements.txt ... lambdaで使うライブラリを定義
└── terraform
    ├── Dockerfile ... terraformのイメージを使う。zipやmake等必要なツールをインストール
    ├── build ... lambda_builderでビルドした結果が配置される。terraformのコンテナから参照してlambdaをdeployする
    │   ├── func
    │   └── func.zip
    ├── lambda.tf ... lambdaをdeployする
    └── provider.tf ... terraformの基本設定

実装時の注意点・ハマりどころ

  • lambda_builderのDockerfileで指定するpythonバージョンと、lambda.tfで指定するバージョンは必ず合わせること。
    バージョン不一致の場合、ModuleNotFoundError: No module named 'psycopg2._psycopg'などのエラーが発生します。

まとめ

以上の方法で、localstackとterraformを連携させ、layerありのlambdaをローカルで効率的にデプロイできるようになりました!!!

開発用のlocal環境などは、その時にすぐできる方法でやってしまいがちですが、ちゃんと考えて作るのは大事ですね。


脚注
  1. 例えば以下のように実行できます。
    python -c 'import index; print(index.handler({}, {}))' ↩︎

Discussion