はじめに
Node.jsランタイムのLambda上で、firebase-admin
モジュールを利用してfirestoreを操作しようとしたときエラーが起きました。
エラーが起きた原因はfirebase-admin
で利用しているgrpc
がネイティブモジュールであることが原因で解決できたのでメモ程度にまとめました。
Lambdaとは
AWSのFunction as a Serviceです。
Httpリクエストやスケジューリングでイベントを発火して、事前に用意しておいたコードを実行させることができます。
Nodejs、Python、Ruby、Java、Go、.NETで書かれたコードを実行させることができます。
Lambdaの環境
・オペレーティングシステム – Amazon Linux
・AMI – amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2
・Linux カーネル – 4.14.77-70.59.amzn1.x86_64
・AWS SDK for JavaScript – 2.290.0
・SDK for Python (Boto3) – 3-1.7.74 botocore-1.10.74
Node.jsのネイティブモジュールとは
Node.jsで利用できるモジュールの中にC/C++で書かれているものがあります。
そのようなモジュールはクロスプラットフォームのコマンドラインツールでビルドしてから利用できるようになっています。
そのようなモジュールはネイティブモジュールと呼ばれ、ビルドされたモジュールは違うOSでは動かないことが多々あります。
つまり、MacやWindowsPCのローカル環境でネイティブモジュールをインストールして、そのモジュールを利用したコードを書きLambdaで実行させようとするとOSの違いでうまく動かないことがあるということです。
Lambdaでネイティブモジュールを利用する方法
Lambdaでネイティブモジュールを利用したい場合、Amazon LinuxというOSで動くモジュールを準備する必要があります。
Amazon Linuxの環境を構築して、その環境内でモジュールをインストールすればいいので、Dockerの出番です。
Dockerが使えない場合、Dockerを使えるようにしておいてください。
Amazon LinuxのContainer起動
AmazonはAmazon Linuxのイメージを公開しているので、プルしましょう。
docker pull amazonlinux:latest
PCのボリュームをマウントして、Amazon Linuxイメージでコンテナーを対話モードで起動します。
※下記のコマンドではtempというフォルダをマウントしています。
docker run -it -v $PWD/temp:/temp --name native-module-sample amazonlinux:latest
Node.jsを利用できるようにする
rpmを利用できるようにする。
curl -sL https://rpm.nodesource.com/setup_8.x | bash -
yumでネイティブモジュール利用に必要なものをインストールする。
yum install gcc-c++ make
yumでパッケージマネジャーのyarnをインストールする。
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | tee /etc/yum.repos.d/yarn.repo
yum install yarn
yumでNode.jsをインストールする。
yum install -y nodejs gcc-c++ make
これで、8系のNode.jsとnpmが利用できるはずです。
ネイティブモジュールをインストールしてみる
ローカルPCのtempフォルダをマウントしているので、マウント先でネイティブをインストールします。
※下記のコマンドではfirebase-admin
をインストールしています。firebase-admin内で利用しているgrpcがネイティブモジュールです。
cd temp
npm init -y
npm install firebase-admin
インストールが終了したら、ローカルPCのマウントしているフォルダを確認しましょう。
node_modules
ができているはずです。
nodejs/node_modules/*の構成でzip化してLambda Layerとしてアップロードしましょう。
後は、Layerを登録したLambdaにモジュールを利用したコードをアップロードすれば実行できるはずです。
さいごに
ローカル環境ではうまく動くのにLambda上では動かない原因として、ネイティブモジュールが関わっている場合もあります。エラーで行き詰まっていたら一度ネイティブモジュールの存在も疑ってみてもいいかもしれません。