【AWS SAM】Python版入門

# 内容
samがアップデートされて使いやすくなったらしいので、Pipenvでの環境構築からデプロイまでの流れを備忘録として残しておこうと思います。

# 環境
- macOS Mojave -10.14
- python3.7.4
- sam 0.38.0

# 目次
1. Pipenvで環境構築
2. アプリケーションの初期化
3. デプロイ

# 1. Pipenvで環境構築

### Pipenvインストール
```
$ pip install pipenv
```

### Pipenv初期化
```
$ pipenv --python 3.7
```

### 仮想環境に入る
```
$ pipenv shell
```

### aws-sam-cliインストール
開発時に必要なライブラリは`--dev`オプションをつけることで別枠に出来ます

```
$ pipenv install aws-sam-cli --dev
```

# 2. アプリケーションの初期化

この後の作業のため、`Project name [sam-app]:` はpipfile等があるディレクトリと同じ名前にしましょう。

### テンプレートアプリケーションの生成
```
$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Which runtime would you like to use?
        1 - nodejs12.x
        2 - python3.8
        3 - ruby2.5
        4 - go1.x
        5 - java11
        6 - dotnetcore2.1
        7 - nodejs10.x
        8 - nodejs8.10
        9 - python3.7
        10 - python3.6
        11 - python2.7
        12 - java8
        13 - dotnetcore2.0
        14 - dotnetcore1.0
Runtime: 9

Project name [sam-app]:   aws-sam-1       

Allow SAM CLI to download AWS-provided quick start templates from Github [Y/n]: y

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
Template selection: 1

-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: python3.7
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./aws-sam-1/README.md
```

ここまでの作業で、ディレクトリ構成はこのようになっているハズです。

```
.
├── Pipfile
├── Pipfile.lock
├── README.md
└── aws-sam-1
    ├── README.md
    ├── events
    │   └── event.json
    ├── hello_world
    │   ├── __init__.py
    │   ├── app.py
    │   └── requirements.txt
    ├── template.yaml
    └── tests
        └── unit
            ├── __init__.py
            └── test_handler.py
```

ただ、フラットな方がいいのいで `aws-sam-1/` 以下を一つ上の階層に持ってきます。

```
$ mv ./aws-sam-1/* ./
$ rm -r ./aws-sam-1
```

実行後のディレクトリ階層はこんな感じです。
1リポジトリで複数テンプレートを管理することってあまり無いので、こちらの方がスッキリしていて好きです。

```
.
├── Pipfile
├── Pipfile.lock
├── README.md
├── events
│   └── event.json
├── hello_world
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    └── unit
        ├── __init__.py
        └── test_handler.py
```

### アプリケーションのビルド

```
$ sam build
```

```
Building resource 'HelloWorldFunction'
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```

実行すると、`.aws-sam/` 以下に色々できます。
詳しくは解説しませんが、実際にデプロイされる実行スクリプトやtemplate.yaml、ライブラリなどです。

# 3. デプロイ

さて、ようやくデプロイですが、アップデートによってここが一番簡単になったと思います。

以前は、毎回`sam package`でソースコードや依存ファイルのアップデート等を行い、デプロイ時にはスタック名も指定しなければならないと、割と面倒でした。
アップデート後は、`--guided` オプションをつけることで、それらを `samconfig.toml` というファイルにまとめてくれるようになりました。
これにより、2回目以降のデプロイは、 `sam deploy` コマンドのみでOKになります。

では、アップデート後のデプロイをやっていきましょう。
`~/.aws/credentials`で設定を分けている方は、`--profile` オプションを付けてください。

### デプロイ

```
$ sam deploy --guided
```

```
Configuring SAM deploy
======================

        Looking for samconfig.toml :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: aws-sam-1-stack  
        AWS Region [us-east-1]: ap-northeast-1              
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        Save arguments to samconfig.toml [Y/n]: 

        Looking for resources needed for deployment: Not found.
        Creating the required resources...
        Successfully created!

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-1np75dr62k62n
                A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at 
        https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

        Deploying with following values
        ===============================
        Stack name                 : aws-sam-1-stack
        Region                     : ap-northeast-1
        Confirm changeset          : True
        Deployment s3 bucket       : aws-sam-cli-managed-default-samclisourcebucket-1np75dr62k62n
        Capabilities               : ["CAPABILITY_IAM"]
        Parameter overrides        : {}

Initiating deployment
=====================
Uploading to aws-sam-1-stack/7f10f61137bc6dbef4059bf50229b958  532293 / 532293.0  (100.00%)
Uploading to aws-sam-1-stack/0797e53a6d5052f23f1972e20e6fd8dd.template  1102 / 1102.0  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                                           LogicalResourceId                                                   ResourceType                                                      
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                                               HelloWorldFunctionHelloWorldPermissionProd                          AWS::Lambda::Permission                                           
+ Add                                                               HelloWorldFunctionRole                                              AWS::IAM::Role                                                    
+ Add                                                               HelloWorldFunction                                                  AWS::Lambda::Function                                             
+ Add                                                               ServerlessRestApiDeployment47fc2d5f9d                               AWS::ApiGateway::Deployment                                       
+ Add                                                               ServerlessRestApiProdStage                                          AWS::ApiGateway::Stage                                            
+ Add                                                               ServerlessRestApi                                                   AWS::ApiGateway::RestApi                                          
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:changeSet/samcli-deploy1576913429/1265b6b9-05ac-4a26-9f75-d81099274672


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2019-12-21 16:30:55 - Waiting for stack create/update to complete

CloudFormation events from changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                     ResourceType                                       LogicalResourceId                                  ResourceStatusReason                             
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                                 AWS::IAM::Role                                     HelloWorldFunctionRole                             Resource creation Initiated                      
CREATE_IN_PROGRESS                                 AWS::IAM::Role                                     HelloWorldFunctionRole                             -                                                
CREATE_COMPLETE                                    AWS::IAM::Role                                     HelloWorldFunctionRole                             -                                                
CREATE_IN_PROGRESS                                 AWS::Lambda::Function                              HelloWorldFunction                                 -                                                
CREATE_IN_PROGRESS                                 AWS::Lambda::Function                              HelloWorldFunction                                 Resource creation Initiated                      
CREATE_COMPLETE                                    AWS::Lambda::Function                              HelloWorldFunction                                 -                                                
CREATE_IN_PROGRESS                                 AWS::ApiGateway::RestApi                           ServerlessRestApi                                  -                                                
CREATE_IN_PROGRESS                                 AWS::ApiGateway::RestApi                           ServerlessRestApi                                  Resource creation Initiated                      
CREATE_COMPLETE                                    AWS::ApiGateway::RestApi                           ServerlessRestApi                                  -                                                
CREATE_IN_PROGRESS                                 AWS::Lambda::Permission                            HelloWorldFunctionHelloWorldPermissionProd         -                                                
CREATE_IN_PROGRESS                                 AWS::Lambda::Permission                            HelloWorldFunctionHelloWorldPermissionProd         Resource creation Initiated                      
CREATE_IN_PROGRESS                                 AWS::ApiGateway::Deployment                        ServerlessRestApiDeployment47fc2d5f9d              -                                                
CREATE_COMPLETE                                    AWS::ApiGateway::Deployment                        ServerlessRestApiDeployment47fc2d5f9d              -                                                
CREATE_IN_PROGRESS                                 AWS::ApiGateway::Deployment                        ServerlessRestApiDeployment47fc2d5f9d              Resource creation Initiated                      
CREATE_IN_PROGRESS                                 AWS::ApiGateway::Stage                             ServerlessRestApiProdStage                         -                                                
CREATE_IN_PROGRESS                                 AWS::ApiGateway::Stage                             ServerlessRestApiProdStage                         Resource creation Initiated                      
CREATE_COMPLETE                                    AWS::ApiGateway::Stage                             ServerlessRestApiProdStage                         -                                                
CREATE_COMPLETE                                    AWS::Lambda::Permission                            HelloWorldFunctionHelloWorldPermissionProd         -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         aws-sam-1-stack                                    -                                                
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Stack aws-sam-1-stack outputs:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
OutputKey-Description                                                                                 OutputValue                                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HelloWorldFunctionIamRole - Implicit IAM Role created for Hello World function                        arn:aws:iam::xxxxxxxxxxxx:role/aws-sam-1-stack-HelloWorldFunctionRole-PB5A5G9O9MBP                  
HelloWorldApi - API Gateway endpoint URL for Prod stage for Hello World function                      https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/                             
HelloWorldFunction - Hello World Lambda Function ARN                                                  arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:aws-sam-1-stack-                                
                                                                                                      HelloWorldFunction-1QOQ29MG7346Z                                                                    
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - aws-sam-1-stack in ap-northeast-1
```

これでデプロイが完了しました。

```
HelloWorldApi - API Gateway endpoint URL for Prod stage for Hello World function https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
```
ログに、APIGatewayへのアクセスポイントが表示されているので、アクセスしてみましょう。

```
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
```

```
{"message": "hello world"}
```

と返ってくれば成功です。

# 終わりに

今回はチュートリアル用のアプリをそのまま使いましたが、
次回はDynamoDBを組み合わせてAPIを作っていきたいと思います。

リポジトリ： https://gitlab.com/tarte9572/aws-sam-1