Lambda Layersで自作モジュールを共通ライブラリ化する [Python,Node.js]

# はじめに
Lambda Layersを用いることで、モジュールを共通ライブラリとして、複数のLambdaで使用できるようなので、PythonとNode.jsのパターンで方法をまとめます。

メリットとして、Lambdaのソースコードの量を減らすことができること、各Lambdaごとにモジュールをアップする手間がなくなることがあげられます。

Lambda Layersについて
>Lambda レイヤーは、追加のコードやデータを含めることができる .zip ファイルアーカイブです。レイヤーには、ライブラリ、 カスタムランタイム 、データ、または設定ファイルを含めることができます。レイヤーを使用すると、コードの共有と責任の分離を促進し、ビジネスロジックの記述をより迅速に繰り返すことができます。

# 自作モジュールのディレクトリ構造

Lambda Layersにアップロードされたモジュールは、`/opt`の領域に展開されます。
そのため、指定されたディレクトリ（`下記の表参照`）にPythonモジュールを格納してアップロードすることでLambdaを実行した際にモジュールとして自動的に読み込むことができます。

`各 Lambda ランタイムのレイヤーパス`

|言語 |パス|
|---|---|
| Node.js | nodejs/node_modules |
| 〃|nodejs/node14/node_modules (NODE_PATH)|
|Python|python|
| 〃|python/lib/python3.9/site-packages (サイトディレクトリ)|

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


# モジュールを作成 [Node.js]

```js:today.js
module.exports = () => {
  const dateUTC = new Date();

  // JSTに変更後、タイムスタンプに変える
  const dateJST = new Date(dateUTC.getTime() + 32400000);

  // タイムスタンプを日付の年月日に変える。時間は切り捨て
  let year = dateJST.getFullYear();
  let month = dateJST.getMonth() + 1;
  let day = dateJST.getDate();

  // 値が1桁であれば '0'を追加
  if (month < 10) month = '0' + month;
  if (day < 10) day = '0' + day;

  //"2022-01-16"
  const result = year + '-' + month + '-' + day;

  return result;
};
```

```js:day_after
module.exports = (days_after_number) => {
  const dateUTC = new Date();
  // days_after_number日分、進める
  const days_after_UTC = new Date().setDate(
    dateUTC.getDate() + days_after_number
  );

  const days_after_JST = new Date(days_after_UTC + 32400000);

  let days_after_year = days_after_JST.getFullYear();
  let days_after_month = days_after_JST.getMonth() + 1;
  let days_after_day = days_after_JST.getDate();

  if (days_after_month < 10) days_after_month = '0' + days_after_month;
  if (days_after_day < 10) days_after_day = '0' + days_after_day;

  const result =
    days_after_year + '-' + days_after_month + '-' + days_after_day;

  return result;
};
```

上記の2つのファイルを自作モジュールとして使用します。
ローカルで、ディレクトリを作成し、モジュールファイルを入れて、zip化します。

```
$ mkdir nodejs             
$ cd nodejs 
$ mkdir node_modules
$ cd node_modules 
$ pwd
/nodejs/node_modules
```
`node_modules`ディレクトリ内に、`today.js`と`days_after.js`を入れます。

```
nodejs
└── node_modules
    ├── days_after.js
    └── today.js
```

zip化します。zip名は何でも良いですが今回は、nodejs_layerという名前でzip化します。

```
$ zip -r nodejs_layer nodejs
```

# モジュールを作成 [Python]

pythonの方は、複数のロジックを1つのファイルにまとめることができます。

```py:python_layer.py
from datetime import datetime, timedelta
import boto3

# Method

def today():
    # 2022-01-16 20:54:05.134159
    dateJST = datetime.today() + timedelta(hours=9)
    # 2022-01-16
    return dateJST.strftime("%F")

def days_after(days_after_number):
    dateJST = datetime.today() + timedelta(hours=9)
    days_after_JST = dateJST + timedelta(days=days_after_number)

    return days_after_JST.strftime("%F")

# Table
dynamodb = boto3.resource('dynamodb')
dynamodb_table = dynamodb.Table("users")

# Constant
TYPE = 'all'

```

```
$ mkdir python             
```


```
python
└── python_layer.py
```

zip化します。python_layerという名前でzip化します。

```
$ zip -r python_layer python
```

# Lambda Layerにアップロード[Python,Node.js共通]
`レイヤーの作成`をクリックします。
![スクリーンショット 2022-01-30 10.10.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/db4c7dea-dca5-ba03-d52d-906e875c7f05.png)
互換性のあるランタイムは、作成したLayerと同じ言語を指定します。
zip化したファイルをアップロードし、作成をクリックします

![スクリーンショット 2022-01-30 10.16.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/04e3746f-daf8-0ca7-ba5d-03c2d93998ce.png)

Lambdaの最下部の`レイヤーを追加`をクリックします。
![スクリーンショット 2022-01-30 10.17.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/2e498f21-820c-5d83-e712-a43c789f7bfd.png)
`カスタムレイヤー`から選択し、追加します。
![スクリーンショット 2022-01-30 10.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/06fd58bd-30be-449c-589c-257f2af165f5.png)

# Lambda Layerの呼び出し方法[Node.js]

## メソッド

```js:lambda
exports.handler = async (event) => {
  // Layerを使って共通ライブラリ化
  const today = require("today");
  const days_after = require("days_after");
  
  console.log("本日：" + today());
  console.log("3日後：" + days_after(3));
};
```
`require("ファイル名")`で呼び出せます。
実行します。

```
INFO	本日：2022-01-30
INFO	3日後：2022-02-02
```

# Lambda Layerの呼び出し方法[Python]

## メソッド

```py:lambda
#python_layer.pyからLayerを使って共通ライブラリ化
from python_layer import today,days_after
# from python_layer import *

def lambda_handler(event, context):
  return (today() + "と" + days_after(3))
```
`from ファイル名 import メソッド名`で呼び出せます。
また、`from ファイル名 import * `ファイル内のすべてのメソッドが呼び出せます。
実行します。

```
Response
"2022-01-30と2022-02-02"
```

## 定数

```py:lambda
#python_layer.pyからLayerを使って共通ライブラリ化
from python_layer import TYPE

def lambda_handler(event, context):
  return TYPE
```

```
Response
"all"
```

Pythonの方がファイルが1つにまとめられて、よいですね。


# Python外部ライブラリのLayerを使用したい場合

下記のGitHubにすでに作成されている場合、自分でモジュールをインストールしてLayerにアップする必要がありません。
記事を参考にしてください。

![スクリーンショット 2022-02-19 19.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/441de9c8-abb2-67c6-8435-64ae29072151.png)




https://qiita.com/polarbear08/items/202752d5ffcb65595bd9

https://github.com/keithrozario/Klayers/tree/master/deployments/python3.9