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 以下を丸々無視してもいいかもしれない( アプリケーションのコードのみバンドルする )