Kosaku Kurino

Kosaku Kurino

【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ネイティブモジュールをビルドする