まえおき
AWS Lambda の制限にある通り、Lambdaは一つの関数につき250MB、圧縮して50MB以内のソースしかデプロイすることはできません。また、制限緩和申請で解除されることもありません。
しかしLambdaの便利さにどっぷり漬かり、もうサーバ管理には戻れない体になってしまうと、「いや、素直にEC2使えよ」って処理も、全てLambdaで完結させたくなってきます。
そう、serverless-chromeとかね、、
どんな問題が起きたか
"dependencies": {
"@serverless-chrome/lambda”: "^1.0.0-4",
"aws-sdk”: "^2.76.0",
"chrome-remote-interface": "^0.23.2",
"fs-extra": "^3.0.1"
}
できるだけシンプルになるよう頑張ったのですが、これでnode_modulesが220MB越えました。圧縮して70MB。
そしてその殆どはserverless-chromeにある大きなバイナリファイル、、、
詰んだ。
serverless-chromeを使ってちょっと何かやろうとすると、容易に制限を越えてしまう模様です。
「諦めてEC2使う」がベストプラクティスであろうとは思いつつも、サービス的に常に稼働するものではなく、たまに動くだけのものでしたので、「多少処理が遅延してでもLambdaに載せたい」という気持ちがいっぱいです。
対処方法
結論として、もっとも大きいファイルである
@serverless-chrome/lambda/dist/headless_shell
をデプロイ対象から外し、Lambda起動時にS3から動的に取得することで対応できました!
実装上のコツ
- s3からheadless_shellを/tmpに保存します。その際fs.writeFileSync等でそのまま書き込むと実行権限が無くエラーになるため、取得後にchmodします。
const exec = require('child_process').exec;
exec('chmod 777 ' + CHROME_PATH, (err, stdout, stderr) => {
// 何かの処理
});
コンテナが消えなければ/tmpにこのバイナリは残るため、存在チェックをつけておきます。
@serverles-chrome/lambdaはchromePathというパラメータでchromeのバイナリを指定できるので、ここで先ほどDLしたバイナリを渡します。
launchChrome({ chromePath: '/tmp/headless_shell' });
- serverles-chromeのサンプルはasync/awaitで書かれているので、Node6.10で動くようPromiseで書き換えます。
応用の可能性
まだ試していませんが、多分同種の問題に引っかかった時、特定のバイナリだけではなくライブラリ丸ごとS3において、/tmpにDLした後$NODE_PATHに/tmpを加えれば何とかなる気がします。
いや、デプロイ制限が緩和されればこんなこと全く気にする必要はないので、早く制限解除される未来が来てほしいですね。