Lambdaコンソールに直書きしていたコードをAWS SAMに対応させる

## 概要
以前、LambdaをEventBridgeで定期実行するバッチを作ったのだが、
その際、Lambdaのコードをコンソール上に直書きしていた。

そうしたところ以下の問題が発生した
・デプロイの際、手動でコンソール上のコードを書き換える必要がある（めんどくさい＆ミスする）
・テストがローカル環境でできない

この問題を解消するため、既存のLambdaのコードををAWS SAMに対応させてみる
本記事にはその際の手順を載せる

### 今回SAM対応させるアプリケーションの構成
LambdaをEventBridgeで定期実行しているだけ
![スクリーンショット 2022-11-05 17.21.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/813353/b9193cae-b949-7c2e-4ccf-02259971b50a.png)

## 対応後の感想
  - メリット
      - （小規模なら）対応が楽
          - SAM CLIをインストールして、template.yamlを調整するだけ
      - Serverless Landで多数のサンプルが用意されている
      - Lambda関数をローカルでテストできる
      - デプロイが簡単安全
          - デプロイ対象のリソースが複数あってもコマンド一発でできる
          - 手動デプロイじゃなくなったのでミスが減る
      - CloudFormationで管理されるようになる
          - 各AWSリソースの削除が一回でできる
          - アプリケーションの構成が把握しやすくなる
- デメリット
    - 中規模以上のAWS構成に向かない
        - 既存システムを対応させる場合、template.yamlの修正が大変
        - template.yamlに全ての構成を書くため、ステップ数が膨大になりそう
        - 中規模以上ならTerraformなどの他のツールの方が向いていそう


## 対応手順
### AWS SAM CLIのインストール
まずはAWS SAM CLIをインストールする
mac環境だと以下手順となる、前提としてHomebrewがインストールされていること
```
brew tap aws/tap
brew install aws-sam-cli
```

mac以外の環境は[公式の手順](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)を参照

### テンプレートを探す
[Serverless Land](https://serverlessland.com/)というサイトから
自分が作りたい構成のテンプレートを探してDLする

後述するtemplate.yamlをドキュメントを読みながら自前で作成するのは大変なので、作りたい構成に近いテンプレートを改造してゆく

![スクリーンショット 2022-11-05 17.29.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/813353/6f1301b3-7b3a-f4ea-6674-a979408f4c31.png)


### DLしたテンプレートを修正する
今回DLしたテンプレートは以下のような内容

```
root
├── src
│   ├── app.py     # Lambdaで実行されるソース
└── template.yaml　#　SAMの設定ファイル
```

::::note info 
sam initは不要

sam initを実行するとSAMアプリケーションのテンプレートが展開されるが、余計なファイルまで作られてしまう
Serverless LandからDLしたテンプレートを修正する方が早い
:::

#### src配下を置き換える
src配下には、Lambdaで実行するソースを配置する。
今回は、Lambdaコンソールに直書きしていたコードを、そのままapp.pyに上書きした。

依存関係は、requirements.txtを生成してsrc配下に設置すること（pythonの場合）

#### SAMの設定ファイルを調整する
template.yamlには、SAMアプリケーションの設定が書かれている。
ほとんどの設定がこのファイルに記載されており、アプリケーションの構成はこのファイルをみれば分かるようにになっている。
詳細は[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html) 参照


今回、設置したtemplate.yamlは以下、
変更点は定期実行の周期（Schedule）を1分(1 minute)から1日（1 day)にしたのみ
簡単な説明も載せておく

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Create a Lambda function that logs something to the console from a cron job in EventBridge

Resources:
  ScheduledFunction: # リソースの識別名（任意の値を設定）
    Type: AWS::Serverless::Function # リソースタイプ　作りたいLambdaの構成によって変わる
    Properties:
      CodeUri: src/ # lambdaソースコードの場所
      Handler: app.lambda_handler # lambdaがコールされた時に、最初に実行される関数
      Runtime: python3.8
      MemorySize: 128
            
      Events: # このリソース（Lambda）に紐づくイベント
        ScheduledFunctionEvent: # 識別名（任意の値を設定）
          Type: Schedule # イベントタイプ　Lambda上で実行したいイベントによって変わる
          Properties:
            Schedule: rate(1 day) # 実行周期
```
::::note info 
Cloud Formationと互換性あり

AWS SAMのtemplate.yamlはCloud Formationの同設定ファイルの仕様と互換性がある
これは、AWS SAMがCloud Formationを使ってプロジェクトの構成を管理するため。
:::
### ビルド
ソースの配置とtemplate.yamlの調整が終わったら、以下コマンドでビルドを行う
```
sam build
```

- 備考
    - sam buildは依存関係を解決し、ソースコードをビルドする
    - ビルドしたファイルは.aws-samディレクトリに配置される
    - sam buildによって作られたファイルが、後のテストやデプロイに使用される

### テスト
以下コマンドで作成したビルドしたLambda関数をテストできる
```
sam local invoke
```
- 備考
    - sam buildでできたファイルをテストに使うため、buildしないと更新は反映されない
    - テスト実施にdockerを使うため、インストールしておく必要がある
:::note warn
タイムアウトエラー

テスト実行時に
Function 'ScheduledFunction' timed out after 3 seconds
といったエラーが出る場合は、template.yamlのTimeoutプロパティを調整する
Lambdaの処理が終わる前に、リクエストがタイムアウトしてしまっている
:::

### デプロイ
テストが通ったら、以下コマンドでデプロイを行う
--guidedオプションを付けると、コンソール上でデプロイ時の設定を聞かれるので、表示に従って入力を行う
```
sam deploy --guided
```

今回のデプロイ設定は以下、簡単に説明も記載する。
```bash
$ sam deploy --guided

~~ 略

	Setting default arguments for 'sam deploy'
	=========================================
	Stack Name [test-sam-app]:  # CloudFormationのスタック名、任意の名前を設定
	AWS Region [ap-northeast-1]: # デプロイするアプリケーションを構築するリージョン
	Confirm changes before deploy [Y/n]:  # デプロイ時に変更内容を画面表示するか否か
	Allow SAM CLI IAM role creation [Y/n]: # SAMにIAMロールを作成する権限を与えるか否か、与えないと作成できない
	Disable rollback [y/N]: # デプロイ時にエラーが起こった時、前の状態にロールバックするか、コンソール上でエラーを修正して続行できるようにするかの選択肢
	Save arguments to configuration file [Y/n]: # 上記までの設定をファイル保存するか否か
	SAM configuration file [samconfig.toml]: # 保存する設定ファイル名
	SAM configuration environment [default]: # 保存する設定の設定名
```

※ [Disable rollback [y/N]の詳細](https://aws.amazon.com/jp/about-aws/whats-new/2021/08/aws-cloudformation-troubleshoot-errors/)


なお、--guidedオプションを付けるのは初回のみで良い
最初に入力した内容はsamconfig.tomlに保存され、次回以降はこのファイルから設定が参照される

### デプロイ後
sam deployが成功すれば、CloudFormationに今回デプロイしたアプリのスタックが作成されている。
![スクリーンショット 2022-11-05 20.52.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/813353/122b45ce-178b-2f14-6562-3db80afbdc50.png)

作成されるスタックは以下
- test-sam-app
    - LambdaやEventBlidgeが定義されたスタック
- aws-sam-cli-managed-default
    - s3のスタック
    - template.yamlと、Lambdaソースコードをビルドしたバイナリファイル等が保存されている
    - このtemplate.yamlとバイナリファイルを元に、CloudFormationのスタックを作成している


## 削除
削除はSAM CLIではできないようなので、CloudFormation上から行う
![スクリーンショット 2022-11-05 20.58.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/813353/06ec342d-b2d4-3e58-e373-995d613d7838.png)