Lambdaの250MB制限でハマりつくした(Node.js)
Unzipped size must be smaller than 262144000 bytes
って言われたことがありますか?私はあります。
Lambdaには上限緩和ができないハマりポイントとして250MB制限があります。この壁には何度かぶち当たっているのですが、Node.jsだとnode_modulesが大きすぎてひっかかることが多いと思います。Pythonだと機械学習系のライブラリを入れて死ぬとか。そんな時にハマったときの備忘録です。状況としては、NestJSを使ったプロジェクトで、400MBくらいのnode_modulesがありました。
Lambdaの制限について
こちらにあるように、
- zip圧縮後50MB
- zip圧縮前250MB
である必要があります。AWS Layersを使う場合はLayersが単体で250MBまでと勘違いしていた時期もありましたが、どうやらLayersを使う時も解凍後の合計が250MBである必要があります。
これを超過すると冒頭の
Unzipped size must be smaller than 262144000 bytes
が出ます。ちなみにLayersは5レイヤーまで作ることができます。
試したこと
- 全部zipにまとめる
- devDependenciesの切り分け
- その他の手段
- node-prune
- いらないパッケージをrm -rfする
beforeのserverless.yaml
を記載します。
service: hogehoge
frameworkVersion: "2"
plugins:
- serverless-layers
custom:
defaultStage: development
serverless-layers:
layersDeploymentBucket: 適度なバケット名
provider:
name: aws
runtime: nodejs14.x
lambdaHashingVersion: 20201221
region: ap-northeast-1
stage: ${opt:stage, self:custom.defaultStage}
environment:
STAGE: ${self:provider.stage}
apiGateway:
shouldStartNameWithService: true
package:
individually: true
include:
- dist/**
exclude:
- "**"
excludeDevDependencies: true
functions:
index:
handler: dist/handler.handler
events:
- http:
path: /
method: any
- http:
path: "{proxy+}"
method: any
デプロイ手順は以下です
デプロイ手順
- npm install(普通にインストール)
- npm run build(dist/を作る)
- rm -rf node_modules
- npm install --production(devdependenciedを省きたい)
- sls deploy
全部zipにまとめる①serverless-layersをやめる
serverless-layersをやめるとなんとかなるという間違ったお気持ちになって試しました。もちろん失敗します。serverless.yamlからserverless-layersの部分を消して、packagesを以下のように書き換えます。
patterns:
- "!**"
- "node_modules/**"
- dist/**
こうするとdistとnode_modulesがzipにまとまります。何度も言いますが意味がありませんでした。
全部zipにまとめる②手動
さらにハマって混乱した結果、node_modulesをzipに固めてマネジメントコンソールから手動でアップロードを試みました。もちろんこれもだめ。
devDependenciesの切り分け
package.json
の依存モジュールにはdependencies
とdevDependencies
があります。これをうまく切り分けることで軽量化が可能です。切り分け方は
- パッケージをググって
-g
でインストールするようなものはdependencies
にはいらない -
aws-sdk
の類はLambdaに乗っているのでdependencies
にはいらない - @typesは
dependencies
にはいらない - swaggerの類やeslint、prettierも
dependencies
にはいらない - ts-なんとかも
dependencies
にはいらない(ts-node、ts-loaderとか) - typescript自体も
dependencies
にはいらない
こんな感じでどんどんdevDependencies
に切り分けていきます。
du -sh ./node_modules/* | sort -nr | grep '\dM.*'
というコマンドで大きめのファイルを確認できます。また、
du -sh ./node_modules/
でファイルの重さを確認できます。この時点で400MBから100MBちょっとまでpackage.jsonが痩せました。やったね。
ちなみに
上を参考にaws-sdkの中で使うものだけをimportしようと試みましたが、私の環境だとうまくいきませんでした。
その他の方法
node-pruneを使う。パッケージの中のいらないドキュメントなどを削除してくれます。数十MBくらい削減できそう。
もっと減らしたいときは各パッケージの中のdist以外を消すとか、明らかにいらない依存パッケージを目で見て消すとかはできます。
さらに、webpackの設定をいじってminifyするという方法もありそうです。
参考
追記
悩む必要は…なかったのでは…?
Discussion