Lambda Layersを使用して共通ライブラリを作成してみた

## はじめに

この記事は、[ミロゴス Advent Calendar 2023](https://qiita.com/advent-calendar/2023/milogos) 18日目の投稿です。
AWS Lambdaは、サーバーレスコンピューティングを実現するための重要なコンポーネントです。
この記事では、Pythonを使用してAWS Cloud Development Kit (CDK) を活用し、Lambda Layerを作成し、Lambda関数から共通処理を呼び出す方法を簡単に紹介します。

## Lambda Layersとは
Lambda Layersは、AWS Lambdaで提供されている機能の一つです。
共通のコードやリソースを複数のLambda関数で共有し、アプリケーションの効率性と保守性を向上させるための有用なツールです。
特に、多くのLambda関数で同じコードやライブラリを使用する場合や、コードサイズの制約に直面する場合に役立ちます。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/chapter-layers.html

## 内容

### 環境
- 使用する環境の情報です。
```bash
npm -v
10.2.0

python -V               
Python 3.9.6

aws-cdk version
2.96.2
```

### Lambda Layerの準備

#### インポート
必要なライブラリやモジュールをインポートしています。
```python:cdk_stack.py
from aws_cdk import RemovalPolicy, Stack
from aws_cdk import aws_lambda as _lambda
from aws_cdk import aws_lambda_python_alpha as python_lambda
```

#### Layerの作成
```python:cdk_stack.py
layer = _lambda.LayerVersion(
    self,
    "MyLayer",
    removal_policy=RemovalPolicy.DESTROY,
    code=_lambda.Code.from_asset("tmp"),
    compatible_architectures=[_lambda.Architecture.X86_64, _lambda.Architecture.ARM_64],
)
```
- removal_policy=RemovalPolicy.DESTROY
    - Layerの削除ポリシーを設定しています。
    - `RemovalPolicy.DESTROY`を設定すると、CloudFormationスタックが削除された際にLayerも削除されます。
- code=lambda_.Code.from_asset("tmp")
    - Layerの本体であるコードやファイルをどのように提供するかを指定します。
    - ローカルディレクトリの`tmp`ディレクトリからコードを読み込むように指定しています。
- compatible_architectures=[lambda_.Architecture.X86_64, lambda_.Architecture.ARM_64]
    - Lambda Layerと互換性のあるアーキテクチャを指定しています。
    - X86_64（x86_64アーキテクチャ）およびARM_64（ARM_64アーキテクチャ）の両方に対応しています。つまり、このLayerはこれらのアーキテクチャで実行されるLambda関数に使用できます。

Layerのパラメータに関する詳しい説明は以下のリンクからご確認ください。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.LayerVersion.html

#### Lambda Layerのコードをセットアップ
Layerに含めたいコードやファイルを適切な場所に準備します。

```python:app.py
if os.path.isdir("tmp"):
    shutil.rmtree("tmp")
shutil.copytree("src/common", "tmp/python/src/common")
```
この処理は、デプロイ時に`src/common`ディレクトリのコンテンツを`tmp/python/src/common`ディレクトリにコピーします。
Pythonの場合、共通処理はpythonディレクトリ以下に格納されることを想定しています。

パッケージングの詳細については、以下のリンクからご確認ください。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/packaging-layers.html

#### Lambdaの作成
Lambdaを2つ作成して、Layerを呼び出せるようにします。

```python:cdk_stack.py
self.first_lambda = python_lambda.PythonFunction(
    self,
    "first-lambda",
    entry=os.path.join(os.getcwd(), "src/first_lambda"),
    runtime=_lambda.Runtime.PYTHON_3_9,
    index="main.py",
    handler="lambda_handler",
    function_name="first-lambda",
    layers=[layer],
)
self.second_lambda = python_lambda.PythonFunction(
    self,
    "second-lambda",
    entry=os.path.join(os.getcwd(), "src/second_lambda"),
    runtime=_lambda.Runtime.PYTHON_3_9,
    index="main.py",
    handler="lambda_handler",
    function_name="second-lambda",
    layers=[layer],
)
```

- entry=os.path.join(os.getcwd(), f"src/{entry_name}")
    - Lambda関数のコードが含まれるディレクトリまたはZIPファイルの場所を指定します。
- runtime=_lambda.Runtime.PYTHON_3_9
    - Lambda関数のランタイムを指定します。この場合、Python 3.9が使用されています。
- index="main.py および handler="lambda_handler"
    - Lambda関数のエントリーポイントとハンドラー関数を指定します。
    - main.py内のlambda_handler関数がエントリーポイントとして指定されます。
- layers=[layer]
    - Lambda関数に適用するLambda Layerを指定します。

Lambdaのパラメータに関する詳しい説明は以下のリンクからご確認ください。

https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_lambda_python_alpha/PythonFunction.html

#### Layerで提供するコードの作成
共通処理などをまとめます。
今回は確認のための例で、connect_checkメソッドを入れており、値をLambdaから表示します。

```python:common_class.py
class CommonClass:
    # テスト用
    def connect_check() -> str:
        return "CommonClass loading completed"
```

### ディレクトリ構成
最終的なディレクトリ構成は以下になります。
```bash
.
├── README.md
├── app.py
├── cdk
│   └── cdk_stack
│       ├── __init__.py
│       ├── __pycache__
│       └── cdk_stack.py
├── cdk.json
├── package-lock.json
├── package.json
├── poetry.lock
├── pyproject.toml
├── src
│   ├── common
│   │   └── common_class.py
│   ├── first_lambda
│   │   ├── main.py
│   │   └── requirements.txt
│   └── second_lambda
│       ├── main.py
│       └── requirements.txt
└── tmp
    └── python
        └── src
            └── common
                └── common_class.py
```

### 確認

#### Lambdaの手動実行
コンソール上から2つのLambdaのテストを実行してLayerのCommonClassから必要なデータを出力できればOKです。
例では、connect_checkメソッドを使用して"CommonClass loading completed"を出力しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952491/1a0ec347-b835-08cd-ee28-9d1224da03b3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952491/e6e77c82-5dd5-d013-5549-a6fdb800e9e7.png)


### さいごに
Lambda Layersを使用することで、共通のコードやリソースを複数のLambda関数で共有し、コードの再利用性を高めることができます。
AWS CDKなどのツールを使用してLambda Layerを簡単に作成できるため、ぜひ実際に試してみてください。