Node.js
AWS
lambda
Firebase

【AWS】 LambdaでNode.jsネイティブモジュールを利用する


はじめに

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上では動かない原因として、ネイティブモジュールが関わっている場合もあります。エラーで行き詰まっていたら一度ネイティブモジュールの存在も疑ってみてもいいかもしれません。


参考

DockerでAWS Lambda用のNode.jsネイティブモジュールをビルドする