Klayersを参考にAWS Lambda Layersのビルドシステムを内製化した話

こんにちは。バックエンド担当の鈴木です。

本記事では、Klayersを参考にAWS Lambda Layersのビルドシステムを内製化したことについて書きたいと思います。

はじめに

この取り組みを始めた主な目的は、レイヤーの一元管理とレイヤーに含まれるライブラリのバージョン管理です。

AWS Lambdaを利用する開発において、ライブラリの管理は課題となっていました。

特に、Lambda関数で同じレイヤーを使用していても、

ライブラリの依存関係を理由に、異なるバージョンのライブラリを含むレイヤーを作成する必要がある場合があります。

Klayersは、弊社も利用しているビルド済みのAWS Lambda Layersを提供するプロジェクトです。

しかし、pythonのバージョンなどを理由に私たちのニーズに完全に合致させることは難しいと判断し、

Klayersを参考にしながら、ビルドシステムの内製化を進めました。

ここでは、この内製化の過程について共有していきます。

概要

  1. 作業時の流れ
  2. ライブラリ定義ファイル(libraries.json)
  3. バージョン管理と更新スクリプト
  4. ドキュメント(Markdown形式)と更新スクリプト
  5. 今回の実装の工夫点
  6. GitHub Actionsを利用した自動化ワークフロー

1. 作業時の流れ

実際の運用時は以下の手順で進めます:

  1. AWS Lambda Layersにアップロードするpythonバージョン、含めるライブラリを指定する。 「2. ライブラリ定義ファイル(libraries.json)」にあたります。
  2. 各ライブラリのバージョンの割り当て/更新スクリプトを実行する。 「3. バージョン管理と更新スクリプト」にあたります。
  3. githubに上げる。 この時「6. GitHub Actionsを利用した自動化ワークフロー」が実行されます。

2. ライブラリ定義ファイル(libraries.json)

[
{
"layer_name": "SQLAlchemy",
"libraries": {
"python3.12": [
"SQLAlchemy==2.0.31"
]
}
},
{
"layer_name": "SQLAlchemy_pandas",
"libraries": {
"python3.8": [
"SQLAlchemy==2.0.31",
"pandas==2.0.3"
],
"python3.12": [
"SQLAlchemy==2.0.31",
"pandas==2.2.2"
]
}
}
]

この JSON ファイルで、必要なライブラリとそのバージョンを定義します。

※ ライブラリのバージョン指定方法については「3. バージョン管理と更新スクリプト」に補足説明があります。

3. バージョン管理と更新スクリプト

このスクリプトは、ライブラリのバージョンの割り当て/更新を自動化します。


このスクリプトの内容は以下の通りです:

  • ライブラリ情報の読み込み libraries.json ファイルから指定しているライブラリを読み込みます。
  • Dockerを利用した環境分離 各Pythonバージョンに対応したDockerイメージを使用し、ライブラリのインストールとバージョン確認を行います。
  • 最新バージョンの取得 指定されたライブラリを一時的なDockerコンテナ内でインストールし、最新のバージョン情報を取得します。
  • バージョンの割り当て/更新 取得した最新バージョン情報を元に、libraries.json ファイルのライブラリに対してバージョンの割り当て/更新をします。


バージョンの割り当て/更新

スクリプト実行前のlibraries.json

[
{
"layer_name": "SQLAlchemy",
"libraries": {
"python3.12": [
"SQLAlchemy==2.0.29"
]
}
},
{
"layer_name": "SQLAlchemy_pandas",
"libraries": {
"python3.8": [
"SQLAlchemy",
"pandas"
],
"python3.12": [
"SQLAlchemy",
"pandas"
]
}
}
]


スクリプト実行後のlibraries.json

[
{
"layer_name": "SQLAlchemy",
"libraries": {
"python3.12": [
"SQLAlchemy==2.0.31"
]
}
},
{
"layer_name": "SQLAlchemy_pandas",
"libraries": {
"python3.8": [
"SQLAlchemy==2.0.31",
"pandas==2.0.3"
],
"python3.12": [
"SQLAlchemy==2.0.31",
"pandas==2.2.2"
]
}
}
]

このように、最新のライブラリのバージョンを割り当て/更新してくれます。

このスクリプトの利点:

環境の一貫性: Dockerを使用することで、ローカル環境に依存せず、常に一貫した結果を得られます。 自動化: 手動でのバージョン確認や更新作業が不要になり、人的ミスを減らせます。 柔軟性: 新しいPythonバージョンやライブラリの追加に容易に対応できます。 安全性: 実際のLambda環境に影響を与えることなく、バージョン更新のテストができます。

4. ドキュメント(Markdown形式)と更新スクリプト

内製化したシステムの特徴として、各レイヤーの詳細情報を簡単に確認できる仕組みを実装しました。

具体的には、以下のような形式でMarkdownファイルをスクリプトで自動生成/更新します。

## Python 3.8 Libraries

| ARN | Package | Package Version | Last updated date |
|-----|---------|-----------------|-------------------|
| {Amazon Resource Name (ARN)} | {レイヤーに含まれているライブラリ名} | {各ライブラリのバージョン} | {最終更新日時} |
| {Amazon Resource Name (ARN)} | {レイヤーに含まれているライブラリ名} | {各ライブラリのバージョン} | {最終更新日時} |

この形式により

  • ARN
  • レイヤーに含まれるライブラリ名
  • 各ライブラリのバージョン
  • 最終更新日

を一目で確認することができます。

また、これらの情報はPythonバージョンやAWSリージョンごとに整理しています。


ディレクトリ構造

aws-lambda-layers/
├── deployments/
│ ├── python3.8/
│ │ └── ap-northeast-1/
│ │ └── libraries.md(本ドキュメント)
│ └── python3.12/
│ └── ap-northeast-1/
│ └── libraries.md(本ドキュメント)
├── 本スクリプト
└── ...

この構造により、異なるPythonバージョンやAWSリージョンのレイヤー情報を簡単に参照できます。

5. 今回の実装の工夫点

今回、工夫を要した点は、libraries.json の更新に基づいて、

変更があったレイヤーのみを AWS Lambda Layers にアップロードする仕組みの構築です。


当初は libraries.json ファイルのみで差分の検出を試みましたが、

libraries.json のみでは、正確に追跡することが困難だったため、下記のようにして解決しました。


libraries.json の内容に基づいて、_libraries ディレクトリ内に各レイヤーのサブディレクトリが動的に生成/更新されるスクリプトを実装する。

_libraries ディレクトリを対象に git diff で差分を検出し、更新があったレイヤーのみ AWS Lambda Layers にアップロードする。


ディレクトリ構成(_libraries ディレクトリ配下はスクリプトで生成されたもの)

_libraries/
├── SQLAlchemy/
│ └── python312/
│ └── requirements.txt
├── SQLAlchemy_pandas/
│ ├── python38/
│ │ └── requirements.txt
│ └── python312/
│ └── requirements.txt
├── 本スクリプト
└── ...

<SQLAlchemyレイヤー(Python 3.12)のrequirements.txt>

SQLAlchemy==2.0.31

<SQLAlchemy_pandasレイヤー(Python 3.8)のrequirements.txt>

SQLAlchemy==2.0.31
pandas==2.0.3

<SQLAlchemy_pandasレイヤー(Python 3.12)のrequirements.txt>

SQLAlchemy==2.0.31
pandas==2.2.2

このように、_libraries ディレクトリ内に各レイヤーのサブディレクトリが動的に生成/更新されるスクリプトを実装することで、

差分検出が容易になり、変更があったレイヤーのみをAWS Lambda Layersに再アップロードする仕組みができました。

6. GitHub Actionsを利用した自動化ワークフロー

弊社では master ブランチと作業ブランチで運用し、master にマージされ、libraries.json が更新された場合にのみ、本GitHub Actionsが実行されます。

このGitHub Actionsでは以下の処理を行います:

  • 更新があったレイヤーの検出(「5. 今回の実装の工夫点」に補足説明があります)
  • ライブラリのインストールと ZIP の作成
  • 作成した ZIP を AWS Lambda Layers へアップロード
  • ドキュメントの自動生成/更新(「4. ドキュメント(Markdown形式)と更新スクリプト」のスクリプトが実行されます)

さいごに:今後の計画

ビルドプロセスのパフォーマンス向上

現状、特定のリージョンと特定のPythonバージョンのみ必要なため問題にはなっていませんが、

今後リージョンが増えたり、Pythonバージョンが増えた場合には、

ビルドプロセスの並列化やクロスリージョンレプリケーションの自動化が必要になるかもしれません。


本記事では、Klayersを参考にしたAWS Lambda Layersのビルドシステム内製化について、その背景から実装の詳細を解説してきました。

AWS Lambda Layersの管理でお悩みの方々にとって、この記事が何かしらのヒントになれば幸いです。