Lambdaの関数とレイヤーのストレージがデフォルト上限(75GB)に達してしまった時に対応したこと

serverless-prune-pluginで、簡単にLambdaの関数とレイヤーのストレージを節約!
2021.12.02

はじめに

オペレーション部サービスグロースチームの筧です。

先日、チーム用のAWSアカウントで以下のエラーが発生しました。 当該エラーの概要と実施した対処方法をご紹介します。

You've exceeded your account's function and layer storage limit for this Region (75.0 GB).

エラー概要

Serverless FrameworkでLambdaをデプロイしようとした時に当該エラーが発生しました。 AWS公式ドキュメントには当該エラーについて以下の記載がありました。

Lambda クォータ

リソース
アップロードされた関数 (.zip ファイルアーカイブ) とレイヤーのストレージ。各関数バージョンとレイヤーバージョンは、ストレージを消費します。

デフォルトのクォータ
75 GB

引き上げることができる最大
Terabytes

上記から、Lambdaの関数とレイヤーのストレージが、デフォルトのクォータの75GBに達してしまったのだろうと判断しました。 Serverless FrameworkはAWSから以前のバージョンの関数を削除しないため、改修を繰り返すたびに以前のバージョンの関数が積み上がってしまっていたようです。

実施した対処方法

はじめに、暫定対応としてService Quotasによる上限緩和を検討しました。 前述のAWS公式ドキュメントに、「引き上げることができる最大」が「Terabytes」と記載があったとおり、Service Quotasによる上限緩和が可能です。 申請した結果、数時間で150GBに緩和いただけました。

次いで、恒久対応としてServerless Frameworkのプラグインである、serverless-prune-pluginの利用を検討しました。 serverless-prune-pluginは下記の通り、指定したバージョン(3世代前とか)の関数などは残して後は消してくれるプラグインです。

Serverless Prune Plugin

Following deployment, the Serverless Framework does not purge previous versions of functions from AWS, so the number of deployed versions can grow out of hand rather quickly. This plugin allows pruning of all but the most recent version(s) of managed functions from AWS. This plugin is compatible with Serverless 1.x and higher.

やってみた

serverless-prune-pluginの導入方法をご紹介します。

既存のディレクトリでサービスを開始します。

$ cd {サービスのディレクトリ}
$ serverless create --template aws-python3
Serverless: Generating boilerplate...
Serverless: Successfully generated boilerplate for template: "aws-python3"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name

ディレクトリ階層は以下です。

$ tree
.
├── LICENSE
├── README.md
├── handler.py
└── serverless.yml

Serverlessプラグインコマンドでserverless-prune-pluginをインストールします。

$ sls plugin install -n serverless-prune-plugin
Serverless: Installing plugin "serverless-prune-plugin@latest" (this might take a few seconds...)
Serverless: Successfully installed "serverless-prune-plugin@latest"

ディレクトリ階層は以下のようになります。

$ tree -L 1
.
├── LICENSE
├── README.md
├── handler.py
├── node_modules
├── package-lock.json
├── package.json
└── serverless.yml

serverless.ymlを確認すると、pluginsにserverless-prune-pluginが自動で追加されています。

3世代だけ残して後は自動で削除するために、serverless.ymlを編集します。 下記ハイライトの箇所を追加することで、当該設定ができました。(主旨とは直接関係ないmemorySizeなどを追加しています)

service: serverless-prune-plugin
frameworkVersion: "2"
provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'ap-northeast-1'}
  memorySize: 256
custom:
  prune:
    automatic: true
    number: 3
functions:
  hello:
    handler: handler.hello
package:
  patterns:
    - "!.git/**"
    - "!node_modules/**"
    - "!package-lock.json"
plugins:
  - serverless-prune-plugin

serverless-prune-pluginが機能するか確認してみます。 初回はデプロイが完了した後に、初回バージョンが追加された旨が表示されています。

$ sls deploy --stage dev
{省略}
Serverless: Prune: Running post-deployment pruning
Serverless: Prune: Querying for deployed function versions
Serverless: Prune: serverless-prune-plugin-dev-hello has 1 additional version published and 0 aliases, 0 versions selected for deletion

serverless-prune-pluginが機能するか確認してみます。 handlers.pyの内容を修正して、sls deployを複数回繰り返します。 下記ハイライトの箇所の通り、4回目のデプロイが完了した後に、初回バージョン(3世代より前)は自動で削除されていることが確認できました。

$ sls deploy --stage dev
{省略}
Serverless: Prune: Running post-deployment pruning
Serverless: Prune: Querying for deployed function versions
Serverless: Prune: serverless-prune-plugin-dev-hello has 4 additional versions published and 0 aliases, 1 version selected for deletion
Serverless: Prune: Deleting Function serverless-prune-plugin-dev-hello v1...
Serverless: Prune: Pruning complete.

おわりに

serverless-prune-pluginを利用することで簡単にLambdaの関数とレイヤーのストレージを減らすことができました。 Serverless Frameworkご利用の方は、サービス開始時に当該プラグインを入れてみてはいかがでしょうか。