AWS Lambda で Cloud Firestore を使う
Webpack を利用した複数の Lambda 関数の管理 - kitak blog の続きで色々やっていました。
Cloud Firestore を Lambda から使おうとしたんですが、バンドルファイルを実行したらエラーに。grpc まわりでネイティブモジュールのビルドが必要で、firebase-admin パッケージは Webpack のバンドル対象から除外することにしました。( firebase-sdk-js を使うことも検討したんですが、こちらも結局同じ問題に )
webpack-node-externals
除外には、webpack-node-externalsを使います。これはデフォルトでは、node_modules 以下を全てバンドル対象から外しますが、正規表現で除外対象を絞ることができます。今回の場合、こんなかんじです。
const nodeExternals = require('webpack-node-externals'); module.exports = { mode: 'none', target: 'node', externals: /^firebase-admin/ // ... };
Docker を使ったネイティブモジュールのビルド
ネイティブモジュールのビルドのために Docker を使いました。以下のスクリプトを用意して、postbuild
タスクで実行します(zip を作成する前に実行する)。
Lambda の node バージョンと同じバージョンの node のイメージを使っていますが、本当は Amazon Linux のイメージをベースにした node 入りのイメージを用意したほうがよさそうです。
#!/usr/bin/env node const {promisify} = require('util'); const {exec} = require('child_process'); const execAsync = promisify(exec); (async () => { console.log(`Install native module ...`); await execAsync(`docker run --rm -v "$PWD":/worker -w /worker node:8.10.0 npm i firebase-admin --prefix . --production`, { cwd: './dist/hoge', maxBuffer: 1000*1024, }); })();
今後
- zip のファイルサイズが数十M以上になってしまったので、結局、S3 経由でデプロイする必要がありそう( firebase-admin とそれの依存するパッケージのファイルサイズが大きい... )
- CodeBuild を使って、デプロイのパイプラインを整備する( CodeBuild で Docker が使えたはず )
- Git push or コマンド実行 → CodeBuild で zip の作成 → S3 に zip を配置 → S3 経由で Lambda 関数の更新
- 今回は firebase-admin だけ無視したけれども、webpack-node-externals で node_modules 以下を丸々無視してもいいかもしれない( アプリケーションのコードのみバンドルする )
- 各バンドルファイルに含まれる node_modules 以下のパッケージをリスト化して package.json を動的に生成して、Docker コンテナで install すればよさそう
- GitHub - ubilabs/webpack-node-modules-list: Exports all used node modules of a webpack bundle to a file. を使えばできそう?