見出し画像

AWS LambdaでChart.jsのグラフを画像出力できるかチャレンジ

結論から申しますと、できます。けど、めっちゃ面倒だったので備忘として残します。

なお、この記事を書いた時点(2019/07/07)での例となります。

参考にした資料は以下。

AWS Lambda上でnode-canvasを使ってグラフを描画する
https://tech.studyplus.co.jp/entry/2019/02/25/095548

node-canvas/Installation: AWS Lambda
https://github.com/Automattic/node-canvas/wiki/Installation:-AWS-Lambda

Node.jsのバージョンは10.xを利用しました。


どの資料にも記載されていますが、Node.jsとChart.jsだけでは画像の出力ができないので、chartjs-node-canvasというものを使うのですが、Canvas APIをcairoで再実装したライブラリを利用しているため、このcairoをLambdaが認識できないと(アップロードするnode_modules等にcairoのバイナリがないと)実行できないわけです。

本記事の趣旨は、このcairo込みのnode_modulesを作るのが面倒だという話です。(この面倒な作業を簡単にしたぜ!というものではなく、面倒なので忘れないようにしようという記事)

上資料ではDockerを利用してnode_modulesを構成している例もありますが、私がDocker初心者なので適当にやったら確実に怪我することを考えて、EC2のAmazon Linuxで作業します。とはいえLambdaと同じ環境でビルドしないとそれはそれで怪我をします。なので、Installation: AWS Lambdaに記載の通り、Lambda AMIを利用してEC2を作成します。

Create an EC2 VM from the the Lambda AMI, we'll use this to build canvas and grab compatible libraries.

基本はInstallation: AWS Lambdaの記事通り進めばよいのですが、Node.jsは10.16を利用するためNode.jsのインストールは

nvm install 10.16.0

とする必要があります。また、Node.jsのバージョンを最新化したためか、以下の部分で躓きます。コピーするものが足りないのです。

Then copy the system libraries from /usr/lib64/ into a ./lib/ subdirectory for your Lambda function:
mkdir lib
cp /usr/lib64/{libpng12.so.0,libjpeg.so.62,libpixman-1.so.0,libfreetype.so.6,\
libcairo.so.2,libpango-1.0.so.0,libpangocairo-1.0.so.0,libpangoft2-1.0.so.0} lib/

最終的に必要になったライブラリは以下の通り。

mkdir lib
cp /usr/lib64/{libblkid.so.1,libcairo.so.2,libfreetype.so.6,libjpeg.so.62,\
libmount.so.1,libpango-1.0.so.0,libpangocairo-1.0.so.0,libpangoft2-1.0.so.0,\
libpixman-1.so.0,libpng15.so.15,libuuid.so.1} lib/

ここまで手順通りできたら、ローカルマシンにlibとnode_modulesをダウンロードしAWS Lambda上でnode-canvasを使ってグラフを描画するのサンプルを利用してhandler(index.js)を作成します。

ただし、サンプルのままでは文字化け?フォントがない?などの理由で文字が正しく表示されません。記事末尾でも記載の通りIPAexフォントを利用してLambdaとCanvasがフォントを認識できるようにします。

フォルダ構成でいうとこんな感じ

LambdaFunctionlibnode_modulesindex.jsipaexg.ttfpackage-lock.json

追記するコードは、サンプルを見るとこんな感じ。

const path = require("path");

Canvas.registerFont(path.join(__dirname, 'ipaexg.ttf'), { family: 'ipaex' });

ここで記載されているCanvasという変数ですが、これはnew CanvasRenderService(width, height)で作成したものに該当します。
つまり、

const { CanvasRenderService } = require('chartjs-node-canvas');
const path = require("path");

//中略

const renderService = new CanvasRenderService(800, 600);
renderService.registerFont(path.join(__dirname, 'ipaexg.ttf'), { family: 'ipaex' });

といった形で書いてあげる必要があります。

あとは普通にzipで圧縮してlambdaの関数としてuploadしてあげれば動くはず。めでたしめでたし。

いいなと思ったら応援しよう!