AWS Cloud9でAWS SAM CLI環境作成～Hello World(Python)まで

# はじめに
複数PCのLocal環境構築が面倒になり、Lambda開発環境にAWS Cloud9を選択してみました。
※開発に使用するPCがWindowsやLinuxと両方あって、環境の違いでハマるのが嫌になったのがCloud9を選択した理由です。
※Cloud9にしたらしたでハマりポイントがありました。。メモとして記事にしようと思います。

# 目次
- AWS Cloud9環境作成
    - 環境設定
- AWS SAM CLI環境作成
    - （事前準備）python3.7に変更
    - （事前準備）linuxbrewインストール
    - （事前準備）AWS SAM LOCAL削除
    - AWS SAM CLIインストール
- Hello World(Python3.7)
    - サンプルプロジェクト作成
    - ビルド
    - ローカル実行
    - s3へデプロイ用ファイル作成
    - AWS環境へデプロイ
    - デプロイしたファイルを実行
    - お片付け

# AWS Cloud9環境作成
## 環境設定
- OS:Ubuntu18.04
- 他は特別な設定なし（環境構築方法の詳細は記事少し古いですが、[過去記事参照](https://qiita.com/icck/items/7705ef6871e261d6535e)）


# AWS SAM CLI環境作成
## （事前準備）python3.7に変更
- pythonは3.7に変更、pipもpython3系が動作するようにします。
- ※エイリアスの変更は私の好みです。

~~~ bash:bash
$ python --version
Python 2.7.15+

$ sudo apt install python3.7

echo "alias python='/usr/bin/python3.7'" >> ~/.bashrc
echo "alias pip='pip3'" >> ~/.bashrc
~~~

## （事前準備）linuxbrewインストール
- 今回、AWS SAM CLIのインストールにlinuxbrewを利用するため事前に設定します。

~~~ bash:bash
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"

$ test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv)
$ test -d /home/linuxbrew/.linuxbrew && eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
$ test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile

$ echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile
~~~

## （事前準備）AWS SAM LOCAL削除
- 私が設定した時の一番のハマりポイントでした。Cloud9は既に古いAWS SAM LOCALが設定済で、これが後続でSAMが動かない不具合を起こしました。
- 削除します

~~~ bash:bash
$ npm uninstall -g aws-sam-local

# インストールされていないことを確認
$ pip uninstall aws-sam-cli
Cannot uninstall requirement aws-sam-cli, not installed

# これをしないと後続でSAM LOCALが邪魔をします。。
$ rm -rf $(which sam)
~~~

## AWS SAM CLIインストール

~~~ bash:bash
$ brew tap aws/tap

$ brew install aws-sam-cli

$ /home/linuxbrew/.linuxbrew/bin/sam
Usage: sam [OPTIONS] COMMAND [ARGS]...

  AWS Serverless Application Model (SAM) CLI
...

$ sam --version
SAM CLI, version 0.19.0

$ ln -sf $(which sam) ~/.c9/bin/sam 
$ ls -la ~/.c9/bin/sam
lrwxrwxrwx 1 ubuntu ubuntu 34 Aug 17 14:10 /home/ubuntu/.c9/bin/sam -> /home/linuxbrew/.linuxbrew/bin/sam
~~~

- 補足：アップグレード方法

~~~ bash:bash
$ brew upgrade aws-sam-cli
~~~

# Hello World(Python3.7)
- 一通り環境が完成しました。[AWSの公式チュートリアル](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html)を見ながら動かしていこうと思います。
- バージョン管理、パッケージ管理は省略します。
- 自分が理解しやすかった順に若干手順を並べ替え＆省略しています。

## サンプルプロジェクト作成
- 「README.md」をまず読みます。
- 作成されたファイル群の詳細説明、コマンド操作説明があり、わかりやすいです。

~~~ bash:bash
$ sam init --runtime python3.7
$ tree
└── sam-app
    ├── README.md < -- ★
    ├── event.json
    ├── hello_world
    │   ├── __init__.py
    │   ├── app.py
    │   └── requirements.txt
    ├── template.yaml
    └── tests
        └── unit
            ├── __init__.py
            └── test_handler.py
~~~

- 以下「hello world」を返却するサンプルプログラムが作成されています。

~~~ python:app.py
import json

def lambda_handler(event, context):

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }
~~~


## ビルド
- 実行前にビルドを行います。

~~~
$ cd sam-app/

$ sam build
2019-08-17 14:28:47 Building resource 'HelloWorldFunction'
2019-08-17 14:28:47 Running PythonPipBuilder:ResolveDependencies
2019-08-17 14:28:48 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
[*] Package: sam package --s3-bucket <yourbucket>
~~~

## ローカル実行
- まずはローカル実行して感覚をつかみます。
- hello world できました。
- ローカルでのテストについては省略します。README.mdにコマンドが記載されています。

~~~
$ sam local start-api
2019-08-17 14:31:14 Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
2019-08-17 14:31:14 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2019-08-17 14:31:14  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)

# 指定されたURLを実行してみます
$ curl http://127.0.0.1:3000/hello
{"message": "hello world"}
~~~


## s3へデプロイ用ファイル作成
- 事前にデプロイ用バケットを作成します。

~~~ bash:bash
$ aws s3 mb s3://<bucketname> --region <region>
~~~

- サンプルをs3へ。

~~~ bash:bash
$ sam package --output-template packaged.yaml --s3-bucket <bucketname>

Uploading to xxx5669a2234b92e0d78d12127135xxx  558700 / 558700.0  (100.00%)
Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /home/ubuntu/environment/sam-app/packaged.yaml --stack-name <YOUR STACK NAME>
~~~

## AWS環境へデプロイ

~~~ bash:bash
$ sam deploy --template-file packaged.yaml --region <region> --capabilities CAPABILITY_IAM --stack-name aws-sam-getting-started

Waiting for changeset to be created..
Waiting for stack create/update to complete

Successfully created/updated stack - aws-sam-getting-started
~~~

## デプロイしたファイルを実行

- CloudFormationの「OutputValue」を確認します。

~~~ bash:bash
$ aws cloudformation describe-stacks --stack-name aws-sam-getting-started --region <region> --query "Stacks[].Outputs"

{
  "OutputKey": "HelloWorldApi",
  "OutputValue": "https://<restapiid>.execute-api.<region>.amazonaws.com/Prod/hello/",
  "Description": "API Gateway endpoint URL for Prod stage for Hello World function"
}
~~~

- AWS上でもhello world できました。

~~~ bash:bash
curl https://<restapiid>.execute-api.us-east-1.amazonaws.com/Prod/hello/
{"message": "hello world"}
~~~

## お片付け
- デプロイしたものを削除します。
- お疲れさまでした。

~~~ bash:bash
$ aws cloudformation delete-stack --stack-name aws-sam-getting-started
~~~