Lambda Layers で最新の AWS SDK を使用する

## Lambda Layersとは
AWS re:Invent 2018で Lambda Layers(以下、Layer) が発表されました。
以前は実行に必要な全てのライブラリを1つのパッケージとしてzip化してデプロイする必要がありました。
Layer では複数の関数で利用されるような一般的なコンポーネントを
1つのzipファイルとしてアップロードして利用することができます。
関数のコードは変更する必要はなく、レイヤー内のライブラリーを参照することができます。

**新機能 – AWS Lambda :あらゆるプログラム言語への対応と一般的なコンポーネントの共有**
https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-use-any-programming-language-and-share-common-components/

本記事ではPythonを例に Lambda Layerで 最新のAWS SDKを利用する方法を記載します。

## LayerにAWS SDKを置くと何がよいのか
Lambdaの実行環境には AWS SDK for JavaScript および Python(Boto3)が含まれています。
以下のドキュメントによれば 2018/12/3時点では各SDKのバージョンは以下の通りです。

> * AWS SDK for JavaScript – 2.290.0
> * SDK for Python (Boto 3) – 3-1.7.74 botocore-1.10.74

**Lambda Execution Environment and Available Libraries**
https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html

これが何を意味するかですが、
AWSのUpdateにより新しく追加されたAPI使用するためには最新のSDKをデプロイパッケージに含める必要がありました。
例えば少し前に追加されたCloudWatchのget-metric-widget-imageを最新のSDKをデプロイせずに実行すると
以下のようなエラーが返されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/1da79177-1261-92bd-69ab-6b5a33e5b388.png)

Layer によりAWS SDKを外出しすることにより、スリムなデプロイパッケージを維持しつつも最新のAPIを使用できます。
特にNode.js、Python、Rubyの場合はデプロイパッケージが3MB未満であれば、
コンソールでコードを確認できるメリットがあります。

## AWS SDKのLayerを作成する
実際にやってみます。

### Layerの作成
まずローカルでLayerのパッケージ(ZIP)を作成します。
外部ライブラリをLayerに含めるには、ランタイム毎に定められたパスのいずれかに配置する必要があります。

* Pythonの場合: **python/** or **python/lib/python3.7/site-packages/** (site directories)
* Node.jsの場合: **nodejs/node_modules** or **nodejs/node8/node_modules** (NODE_PATH)

その他のランタイムも以下のドキュメントに記載があります。
**Including Library Dependencies in a Layer**
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html#configuration-layers-path

Pythonの場合、以下のようにLayerパッケージを作成することができます。

```shell-session
$ mkdir python
$ pip install -t ./python boto3
$ zip -r boto3-1.9.57.zip python
```

次にコンソールでLayerを作成します。
メニューから Layers を選択し、レイヤーの作成をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/e7b32763-ab40-e708-f38d-6362519a3a0a.png)

作成したzipファイルを直接アップロードするか、S3上のパスを記載します。(関数のデプロイと一緒です）
あとはLayerの名前、説明、互換性のあるランタイム、オプションでラインセンス情報を記載し、
作成を選択するだけです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/0213d4e2-14a7-988d-83d0-37e474800048.png)

Layerを追加することができました。簡単ですね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/28e6d33e-2c5f-9d46-5fcb-48133669198e.png)

## LayerをLambda関数に組み込む
Lambda関数から作成したLayerを利用する設定を行います。
デザイナーで関数名の下にあるLayersを選択し、参照されるレイヤーからレイヤーの追加をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/3676be66-ea40-2f78-2aa8-aed25dd96ee4.png)

LayerのARNを入力するか、リストから選択し、接続を押下するだけです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/9ce67397-52c6-f000-6c09-bdf71fc51062.png)

レイヤーを追加したら変更を保存します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/125105/a13eced4-89c4-46ae-8213-a02ac04dc98f.png)

以上で設定は完了です。

## 動作確認
以下のような超簡易コードで確認してみます。

```lambda_function.py
import boto3

def lambda_handler(event, context):
    print(boto3.__version__)
```
### Before(Layer追加前)
1.7.74 です。ドキュメント通り。

```shell-session
START RequestId: f3e23a03-f6f5-11e8-9531-21cb32e1956a Version: $LATEST
1.7.74
END RequestId: f3e23a03-f6f5-11e8-9531-21cb32e1956a
REPORT RequestId: f3e23a03-f6f5-11e8-9531-21cb32e1956a	Duration: 0.32 ms	Billed Duration: 100 ms 	Memory Size: 128 MB	Max Memory Used: 27 MB	
```

### After(Layer追加後)
1.9.57になっています。

```shell-session
START RequestId: c0ec808c-f6f7-11e8-8692-87076a4ebc4a Version: $LATEST
1.9.57
END RequestId: c0ec808c-f6f7-11e8-8692-87076a4ebc4a
REPORT RequestId: c0ec808c-f6f7-11e8-8692-87076a4ebc4a	Duration: 0.35 ms	Billed Duration: 100 ms 	Memory Size: 128 MB	Max Memory Used: 34 MB	
```

## 注意点など
* 1つの関数から参照できるLayerは最大5つまでです
    * 更に展開されたパッケージサイズが250MBを超えることができません
* LayerのZIPファイルは同じパスに展開されるため、上書きに注意が必要です
    * レイヤーのマージ順序を使用することである程度制御できます
* Layerのバージョンを更新した場合、Lambda側でも参照するバージョンを変更する必要があります
* 外部パートナーが提供するLayerを使用することもできます
    * DataDogにLambdaのカスタムメトリックを送信する例
        * [Datadog's Lambda Layer: Monitor custom serverless metrics](https://www.datadoghq.com/blog/datadog-lambda-layer/)

以上です。
参考になれば幸いです。