最近、Lambda関数はServerless Frameworkで管理することが多くなってきました。
Serverless Frameworkでは、一般に「Service」という単位で複数のLambda関数を管理します。
デプロイ自体も、このService単位で行います。
# Service 配下の全 Lambda 関数 (および、付随するリソース)が AWS 環境にデプロイされる $ npx sls deploy
課題
最近課題だったのは、Serverless Frameworkのパッケージングの単位がServiceであるが故に、全ての関数でパッケージが共有され、関数のサイズが大きくなりがちなことでした。
実際にどのようにパッケージングされるかを確認してみます。
まずはパッケージング。
$ npx sls package Packaging serverless for stage dev (ap-northeast-1) ✔ Service packaged (0s)
デフォルトでは、.serverless
ディレクトリにパッケージングされた結果が配置されます。
zipファイルの中身を読むと、複数のLambda関数が一つのzipファイルに同梱されていることがわかります。
これが各Lambda関数で読み込まれるわけで、Lambda関数が多くなればなるほど、個々のLambda関数のサイズも大きくなりますね。
$ ls .serverless ./ ../ cloudformation-template-create-stack.json cloudformation-template-update-stack.json serverless-state.json serverless.zip $ unzip -l .serverless/serverless.zip Archive: .serverless/serverless.zip Length Date Time Name --------- ---------- ----- ---- 696 01-01-1980 00:00 lib.ts 3009 01-01-1980 00:00 middlewares/middleware.ts 276682 01-01-1980 00:00 sample1/handler.js 123219 01-01-1980 00:00 sample2/handler.js --------- ------- 403606 4 files
解決方法
解決方法はPackaging functions separatelyにある通り、package.individually
を使います。
この値をtrue
にすると、パッケージングの単位がServiceからLambda関数に切り替わります。
$ npx sls package Packaging serverless for stage dev (ap-northeast-1) ✔ Service packaged (0s) $ ls .serverless ./ ../ cloudformation-template-create-stack.json cloudformation-template-update-stack.json hello1.zip hello2.zip serverless-state.json
上記ls
の結果としてhello[12].zip
が存在しているように、関数単位でzipファイルができていることがわかります。
また、hello1.zip
の中身を見ると、別のLambda関数であるsample2/handler.js
は含まれていません。
$ unzip -l .serverless/hello1.zip Archive: .serverless/hello1.zip Length Date Time Name --------- ---------- ----- ---- 696 01-01-1980 00:00 lib.ts 3009 01-01-1980 00:00 middlewares/middleware.ts 276682 01-01-1980 00:00 sample1/handler.js --------- ------- 280387 3 files
以下はPackaging functions separatelyになりますが、個々の関数が必要とするファイルはfunctions.func_name.package.patterns
で個別指定すれば良いです。
service: my-service package: individually: true patterns: - '!excluded-by-default.json' functions: hello: handler: handler.hello package: # We're including this file so it will be in the final package of this function only patterns: - excluded-by-default.json world: handler: handler.hello package: patterns: - '!some-file.js'