AWS CloudFormationでのAWS Lambdaの構築方法

業務でAWS CloudFormationを使ったAWS Lambdaのデプロイをする機会があったので、個人的に興味を持ったので自分のメモ代わりとして記事にして残しておきたいと思います。

AWS CLIを利用するので、前もってIAMユーザーやCLIのconfigの設定は完了している前提で進めます。
またLambdaをデプロイする為にAWS SAMというAWS CLIの拡張ツールを使用しますので、こちらもインストールしている前提となってます。

## デプロイまでの流れ
まず、AWS CloudFormationを利用したデプロイは以下の流れとなあります。

1. テンプレートとソースの作成
1. S3にバケットを作成
1. 1で作った作ったテンプレートを元にバケットにLambdaのソースをアップロード
1. 3のテンプレートのフォーマットが正しいかチェックを行いS3にアップロードする
1. 3のテンプレートを元にLambdaに2でアップロードしたソースを反映させて関数を作成する

2度目のデプロイからは3からの作業となります。

## 1. テンプレートとソースの作成
デプロイをする為にはテンプレートとソースが必要です。
テンプレートとソースは以下の構成とします。

```
root/
　├ test-lambda
　│　└ lambda_function.py
　└ templete.yaml
```

`test-lambda`が関数名とします。
`lambda_function.py`の内容についてはコンソールから作成した際にデフォルトで作成される内容をそのまま利用します。

```python:lambda_function.py
import json

def lambda_handler(event, context):
    # TODO implement
    print("success")
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

`templete.yaml`の中身は以下となってます。
コメントは実際は書いてませんが、今回はわかりやすい様に書いておきます。
※あくまで自分的見解なので、間違っている場合は教えて下さるとありがたいです。

```yaml:templete.yaml
AWSTemplateFormatVersion: '2010-09-09' #テンプレートのフォーマットのバージョン
Transform: AWS::Serverless-2016-10-31 # AWS SAMを使用する宣言
Description: 'test' # 説明
Resources: # 作成するLambdaの情報
    TestLambda: #Lambdaの名前
        Type: AWS::Serverless::Function # Lambdaであることを宣言
        Properties: # 実際のLambdaの構成
          FunctionName: test-lambda # Lambdaが作成された時の関数名
          Handler: handler.lambda_handler # 関数のハンドラを指定
          Runtime: python3.9 # 使用するランタイムを指定
          CodeUri: ./test-lambda/ # ローカルのソースコードのパス
          Description: '' #Lambdaの説明
          Role: 'arn:aws:iam::{アカウント ID}:role/service-role/{ロール名}' # Lambdaを管理するロール
```

`{アカウント ID}`と`{ロール名}`については、各自の環境に合わせてください。

## 2. S3にバケットを用意
まず、S3にLambdaに作成したいソースを配置する為のバケットを用意します。
以下のコマンドを実行する事でBucketが作成されます。

``` 
$ aws s3 mb s3://{バケット名} --region {リージョン} --profile {Configで設定したプロファイル名}
make_bucket: {バケット名}
```
{}の内容は各自で都度変更してください。

バケット名には「_」は使用できない様です。
`make_bucket: test-dev-ono`と出たら成功です。
違うログが出た場合はバケット名には使用できない記号を使っているか、リージョン、プロファイル名が間違っている、バケットを作成する権限が無いの何れかだと思いますので各自確認してください。

AWSのコンソールからS3のバケットを開くと以下の様に`test_dev_ono`が作成されてるのがわかります。
![バケット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2191889/40c5a9cc-2e51-34ec-6845-9c4bb72a6ee2.png)

## 3. 作ったバケットにLambdaのソースをアップロード
では、バケットを作成出来たので、ソースをバケットにアップロードします。
以下のコマンドを実行する事でアップロードされます。

```
$aws cloudformation package --template .\templete.yaml --output-template-file .\templete_out.yaml --s3-bucket {バケット名} --profile {Configで設定したプロファイル名}
Uploading to 720f54e373ce3f28bc471d9ad11be6f7  231 / 231.0  (100.00%)
Successfully packaged artifacts and wrote output template to file .\templete_out.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file templete_out.yaml --stack-name {バケット名}
```

```aws cloudformation deploy --template-file templete_out.yaml --stack-name {Configで設定したプロファイル名}```と出ていればアップロードが完了しています。

## テンプレートのフォーマットが正しいかチェック

アップロードが出来たのでこのまま、デプロイしても問題ないですがデプロイの前にデプロイして問題ないかのチェックを行います。
AWS CloudFormationの機能のひとつ変更セットというのを使用してチェックを行いますので、コマンドを2種類入力します。 
以下のコマンドを入力します。

```
$aws cloudformation create-change-set --stack-name {バケット名} --change-set-name test --template-body file://templete_out.yaml --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
arn:aws:cloudformation:{リージョン}:{アカウント ID}:changeSet/test/1e1fb226-3b55-4c64-9bb9-7c1019e8cd15  arn:aws:cloudformation:{リージョン}:{アカウント ID}:stack/{バケット名}/1323dd40-4933-11ec-847c-066265f25571

$ aws cloudformation describe-change-set --stack-name test-dev-ono --change-set-name test
arn:aws:cloudformation:ap-northeast-1:107504602885:changeSet/test/1e1fb226-3b55-4c64-9bb9-7c1019e8cd15  test    2021-11-21T14:57:41.553000+00:00        None    UNAVAILABLE     False   None    None    None    arn:aws:cloudformation:{リージョン}:{アカウント ID}:stack/{バケット名}/1323dd40-4933-11ec-847c-066265f25571      {バケット名}    CREATE_IN_PROGRESS      None    None
CAPABILITIES    CAPABILITY_IAM
CAPABILITIES    CAPABILITY_NAMED_IAM
```

ログの中に`CREATE_IN_PROGRESS`とあれば問題なくデプロ出来るはずです。

## 3テンプレートを元にLambdaをデプロイさせる

やっとデプロイ出来る所まで来ました。
以下のコマンドを入力する事でデプロイが完了します。

```
$aws cloudformation deploy --template-file ./templete_out.yaml --stack-name {バケット名}

Waiting for changeset to be created..
Waiting for stack create/update to complete
```
`Successfully created/updated stack - {バケット名}`と出れば成功です。
最後にAWSのコンソールからデプロイした関数が作成されている事を確認して終了です。

## 最後に
まだまだ、触ったばっかの為調べた事をそのまま実践するしか出来無いので更に詳しく自由に出来る様に学習をして行きたいと思います。
API Gatewayもテンプレートからの作成、更新を行っていける様にしていきたいと思います。