AWS SAM を使って AWS Lambda Layer を作成する

# はじめに

以前に Layer を使って Lambda コンソールの AWS SDK の更新をなるだけコンソールを使って更新する方法を紹介しました（以前の記事は [こちら](https://qiita.com/azureus/items/385ab10b6d12de65ba1f) ）。今回は、同じ内容を AWS SAM を使って行いたいと思います。

## 開発環境を用意する

開発環境には AWS Cloud9 を利用しました。この後の作業を全く同じかたちで実行してみたい方は Cloud9 を用意してください。AWS CLI、SAM CLI が既に用意されているので、この後で必要な操作にたいして準備が必要ありません。Cloud9 の準備には [Cloud9 環境を用意する](https://qiita.com/azureus/items/92f287c164990daefb5b) を参照してください。

## Lambda 関数を作成し、SAM でデプロイする


* 作業を行う work ディレクトリと、 Lambda 関数を格納する my-new-sdk-function2 ディレクトリを用意して、work ディレクトリに移動します。

```
mkdir -p work/my-new-sdk-function2
cd work
```

* Lambda 関数用の ```my-new-sdk-function2.js``` ファイルと、SAM テンプレートを記述する ```template.yaml``` ファイル、SAM CLI 設定用ファイルの ```samconfig.toml``` を用意します。

```
touch my-new-sdk-function2/my-new-sdk-function2.js
touch template.yaml
touch samconfig.toml
```

* my-new-sdk-function2 ディレクトリに ```package.json``` ファイルを用意します。

```
cd my-new-sdk-function2
npm init -y
```

ここまでで、以下のような構成になっていると思います。
![Screenshot_2021-01-17 SampleCloud9 - AWS Cloud9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/b254aaac-5b0b-0897-7593-c8064a6e43d2.png)

* リストから "my-new-sdk-function2.js" を選択し、編集して保存します。

```
const AWS = require('aws-sdk');

exports.handler = async (event) => {
    return AWS.VERSION;
};
```

* リストから "template.yaml" を選択します。SAM テンプレートとしてこのファイルを編集して保存します。

```yaml
AWSTemplateFormatVersion: '2010-09-09' # テンプレートフォーマットの宣言、決まり文句。
Transform: AWS::Serverless-2016-10-31 # AWS SAM テンプレートファイルであることの宣言
Description: Making Lambda Layer # このテンプレートの説明
Resources:
  CallVersionLambda: # リソースの論理名
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: my-new-sdk-function2
      CodeUri: ./my-new-sdk-function2
      Handler: my-new-sdk-function2.handler
      PackageType: Zip
      Runtime: nodejs12.x
      Timeout: 5
      MemorySize: 256
```
__Resources__ には、"my-new-sdk-function2.js" が Lambda として実行されるように値を指定します。まずテンプレート内での名称を宣言します。ここでは ```CallVersionLambda``` としました。次に __Type__ は ```AWS::Serverless::Function``` とします。__Properties__ は、今回、Lambda Layer を使うので __PackageType__ ```Zip``` とし、それに伴い __CodeUri__ , __Handler__ を指定しました。

* "samconfig.toml" ファイルを選択し SAM CLI コマンドのデフォルトパラメータを設定します。バケット名は一意にする必要 ( [バケットの制約と制限 - バケット命名規則](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/BucketRestrictions.html) ) があるので、下で __s3_bucket__ で指定したバケット名とは別の名前を指定してください。

```toml
version=0.1
[default.deploy.parameters]
stack_name = "my-new-sdk-function2"
s3_bucket = "my-new-sdk-function2"
s3_prefix = "call_version_lambda"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
```

ここでは、 __[default.deploy.parameters]__ により　[```sum deploy```](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-deploy.html) コマンドのパラメータ設定を宣言しています。


* "samconfig.toml" ファイルで __s3_bucket__ に指定した S3 バケットを用意します。Cloud9 には AWS CLI が既に用意されているので、ターミナルから ```aws s3 mb s3://<バケット名> ``` コマンドで S3 バケットを用意します。

```
aws s3 mb s3://my-new-sdk-function2
```

* ```sam build``` コマンドを実行してビルドします。

```
cd ~/environment/work
sam build
```

* ビルドが成功したら ```sam deploy``` コマンドを実行してデプロイします。

```
sam deploy
```
途中、changeset をデプロイするか聞かれるので ```y``` を入力して Enter します。
![Screenshot_2021-01-17 SampleCloud9 - AWS Cloud9(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/415ab5d8-d476-e937-f617-ffe47e0d45a7.png)
最終的に "Successfully created/updated stack" と出力されたらデプロイの完了です。

* Lambda コンソールの関数ページを開くと "my-new-sdk-function2" 関数がデプロイされていることを確認できると思います。

![Screenshot_2021-01-17 関数 - Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/f2df9ff5-4567-89dd-bf81-a5721d530586.png)

## 現在の AWS SDK のバージョンを確認する
イベントを用意して、用意した Lambda 関数を呼び出します。

1. 関数一覧から "my-new-sdk-function2" のリンクを選択し、Lambda コンソールの右上にある "テスト" をクリックします。
2. "イベント名" に ```MyNewSdkEvent2``` と名付け、他はデフォルトのまま "作成" をクリックします。
3. もう一度 "テスト" をクリックすると先ほどデプロイした Lambda 関数が実行されます。執筆時点では 2.804.0 でした。

![Screenshot_2021-01-17 my-new-sdk-function2 - Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/1dc63c17-f342-6b26-56c0-e4dad994e982.png)


## SAM で Lambda Layer を作成する

* SAM テンプレートを編集して Layer の設定を追加します。```template.yaml``` ファイルを開いて次の内容に変更してください。追加した部分は、__CallVersionLambda__ リソースのプロパティ __Layers__ と__SdkLayer__ リソースになります。

```yaml
AWSTemplateFormatVersion: '2010-09-09' # テンプレートフォーマットの宣言、決まり文句。
Transform: AWS::Serverless-2016-10-31 # AWS SAM テンプレートファイルであることの宣言
Description: Making Lambda Layer # このテンプレートの説明
Resources:
  CallVersionLambda: # リソースの論理名
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: my-new-sdk-function2
      CodeUri: ./my-new-sdk-function2
      Handler: my-new-sdk-function2.handler
      PackageType: Zip
      Runtime: nodejs12.x
      Timeout: 5
      MemorySize: 256
      Layers: # 追加
        - !Ref SdkLayer
  SdkLayer: # 追加
    Type: AWS::Serverless::LayerVersion
    Properties:
      Description: Newest AWS CDK
      ContentUri: my-new-sdk-layer/
      CompatibleRuntimes:
        - nodejs12.x
    Metadata:
      BuildMethod: nodejs12.x # Required to have AWS SAM build this layer
```

__CallVersionLambda__ リソースの __Layers__ プロパティでは、[```!Ref```](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) を使って Layer の宣言をしているリソース __SdkLayer__ を参照させています。__SdkLayer__ リソースでは __Metadata__ 属性を追加して SAM CLI で [Layer のビルド](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-layers.html) を指定しています。

* __ContentUril__ で指定した Layer のパッケージを追加するディレクトリを作成します。

```
mkdir my-new-sdk-layer
```

* "my-new-sdk-layer" ディレクトリに ```package.json``` ファイルを用意し、最新の AWS SDK をインストールします。

```
cd my-new-sdk-layer
npm init -y
npm install aws-sdk
```

ここまでで、以下のような構成になっていると思います。
![Screenshot_2021-01-17 SampleCloud9 - AWS Cloud9(3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/563c7bb3-0a4f-9d9a-b59c-7a7b7478f65d.png)



* ```sam build``` コマンドでビルドします。

```
cd ~/environment/work
sam build
```

* ビルドが成功したら ```sam deploy``` コマンドを実行してデプロイします。

```
sam deploy
```
途中、changeset の確認で Layer が追加されたことが分かります。確認の後、changeset をデプロイしましょう。

![Screenshot_2021-01-17 SampleCloud9 - AWS Cloud9(2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/b249b629-6a36-c99e-e42e-dee81a6ae129.png)


## 更新後の AWS SDK のバージョンを確認する

まえに用意した "MyNewSdkEvent2" を再度、実行します。Lambda コンソールの右上にある "テスト" をクリックしてください。関数コードペインから実行結果を確認すると更新されたことが確認できると思います。今回は 2.828.0 になりました。

![Screenshot_2021-01-17 my-new-sdk-function2 - Lambda(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743360/4badecc9-eb4f-dc0c-9c00-e951a78b4613.png)

以上です。