理系学生日記

おまえはいつまで学生気分なのか

Serverless FrameworkでLambda関数を個別にパッケージングする

最近、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'