AWS SAM (Serverless Application Model)に触ってみた

# AWS SAMとは

* [GitHubページ](https://github.com/awslabs/serverless-application-model)
* [GitHubのサンプル集](https://github.com/awslabs/serverless-application-model)
* Lambdaとその周辺サービスを構築する際に使う仕組みで、これを使うといい感じで構築管理できるらしい。
* CloudFormationの拡張みたいな感じらしい。
* sam cliを使うとローカルでも開発できるらしい
* とりあえず使ってみる

# 手順

## SAM CLIインストール

要Docker

```
pip install --user aws-sam-cli
sam --version
```

## とりあえず動かしてみる

日時を出力する簡単なLambdaをAWS SAMを使ってデプロイしてみます。

下記ファイルを作成します。

```python:main.py
import logging
import datetime

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
  logger.info("The time is %s", datetime.datetime.now())
```

```yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
  main:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: main.lambda_handler
      Runtime: python3.6
      CodeUri: .
      MemorySize: 128
      Timeout: 10
      Role: !GetAtt lambdaRole.Arn
  lambdaRole:
    Type: "AWS::IAM::Role"
    Properties:
     AssumeRolePolicyDocument:
        Statement:
        - Action: ['sts:AssumeRole']
          Effect: Allow
          Principal:
            Service: ['lambda.amazonaws.com']
        Version: '2012-10-17'
     Path: /
     Policies:
       - PolicyName: Logging
         PolicyDocument:
           Version: '2012-10-17'
           Statement:
             - 
               Effect: "Allow"
               Resource:
                 - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
               Action:
                 - "logs:CreateLogGroup"
             - 
               Effect: "Allow"
               Resource:
                 - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}:*"
               Action:
                 - "logs:CreateLogStream"
                 - "logs:PutLogEvents"
```

AWSにデプロイする前にローカルで実行してみます。

```bash
$ echo '{"key1": "this is key1", "key2": "this is key2", "key3": "this is key3"}' | sam local invoke main
2018-07-11 22:48:24 Mounting /Users/kter/workspace/learning_of_sam/sample1 as /var/task:ro inside runtime container
START RequestId: 70b7d564-94ea-4136-bfa2-05deef1525c7 Version: $LATEST
[INFO]  2018-07-11T13:48:25.539Z        70b7d564-94ea-4136-bfa2-05deef1525c7    The time is 2018-07-11 13:48:25.539234

END RequestId: 70b7d564-94ea-4136-bfa2-05deef1525c7
REPORT RequestId: 70b7d564-94ea-4136-bfa2-05deef1525c7 Duration: 10 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 19 MB

null
```

ここまででローカルでLambdaが動きました。

次にAWSにデプロイするのですが、その前にちょっと説明します。

AWS SAMでは各コンポーネントの設定を記載するtemplate.yamlとLambdaのソースコードであるmain.pyを用意する必要があります (もちろんファイル名は変更できます)。

template.yamlはCloudFormationの形式でLambdaの設定（メモリ量、タイムアウト時間、環境変数等)や他AWSリソースの設定を行います。

最後に実行したsam local invokeコマンドは下記のような書式となります。

```bash
$ sam local invoke (ファンクションID)
```

Lambdaに渡されるパラメータはデフォルトではパラメータは標準入力で、```--event```で渡すこともできます。
※ファンクションIDはtemplate.yaml内でのIDです。

最後にAWSにデプロイしてみます。これには```sam package```と```sam deploy```を実行する必要があります。
sam packageによって一度CloudFormationファイルが生成され、それがS3バケットに設置されます。
sam deployでS3に設置されたCloudFormationファイルが実行され、デプロイが行われます。

```bash
sam package --template-file template.yaml --output-template-file sample1.yaml --s3-bucket (S3バケット名)
sam deploy --template-file sample1.yaml --stack-name sample1 --capabilities CAPABILITY_IAM
```

これでLambdaがデプロイされました。コードの変更時は再度```sam package```と```sam deploy```を実行すればCloudFormationによって自動でデプロイされます。