AWS saｍの環境構築 RubyでLambda実行

# AWS saｍの環境構築
AWS saｍの環境構築をし基本的にAWSの公式ドキュメントをもとに進め、LambdaはRubyで動かす

[Installing the AWS SAM CLI - AWS Serverless Application Model](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)

## 動作環境
MacOS 10.14.2 Mojave

## AWS SAM CLIに必要なものの用意
* Docker
* Python 2.7または3.6のPipコマンド
* AWS CLI: コマンドラインツール

**Dockerのインストール**
Docker for macはすでにインストール済みだが、参考までにDockerもhomebrewコマンドで[Homebrew Cask](http://caskroom.io/)を利用することでこのようにインストールできる

```
brew cask install docker
```

**Pipがインストールされているか確認**
pythonの2.7系か3系が入っていてpipがインストールされていれば良さそうなので、macのデフォルトでpipが使えるかどうかバージョンを確認してみる

```
pip --version
pip 18.1 from /usr/local/lib/python2.7/site-packages/pip (python 2.7)
```

どうやらmacのデフォルトのPython環境にpipがあるので2.7系だがそのまま使うことにする

**AWS CLI: コマンドラインツールのインストール**
awscliのインストールはこちらの公式のページを参考にする
[AWS Command Line Interface をインストールする - AWS Command Line Interface](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html)

こちらのコマンド一発でよい

```
pip install awscli --upgrade --user

# --upgradeオプションはすでにインストール済みのawscliを更新する
# --userオプションは実行ファイルなどシステム領域に置かないようだ。 awsコマンドはここにある /usr/local/bin/aws
# 素の環境のサーバでこのコマンドを入れる場合はこれらのオプションはいらないだろう
```

**aws cliでコンフィギュレーションをする**

[Quick Start - AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html)　より

> Before You Begin
> You must have an AWS account with an IAM user that has administrator permissions.

とあるのでアドミン権限のあるIAMユーザを作成ておく。

*デプロイする際にはCloudformationの権限のみあればいいようなのだが、ローカル開発で必要な権限は何で、デプロイさせない権限の開発者の場合はCloudformationの権限を付けたくない、このような要件については別途調査する。それにしてもこいう説明はAWSのドキュメントってなんかいまいちなんだよなぁ*

cliからコンフィギュレーションを実行する。とりあえずregionはap-northeast-1(東京リージョン)にしておく

```
aws configure
AWS Access Key ID [****************AAAA]:
AWS Secret Access Key [****************BBBBB]:
Default region name [None]: ap-northeast-1
Default output format [None]:
```

python環境をvirtualenvを使って構築している場合は[仮想環境で AWS Command Line Interface をインストールする - AWS Command Line Interface](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-virtualenv.html)を参考にすれば良さそうだ


## AWS SAM CLIをインストールする
インストールする全体条件のものが全て揃ったのでAWS SAM CLIを入れる。
こちらもAWS CLIと同様にpipコマンド一発だ

```
pip install --user --upgrade aws-sam-cli
# --userや--upgradeのオプションもaws-cliと同様の意味
```

# AWS SAM CLIを使ってローカル環境でLambdaを動かしてみる
こちらの公式ドキュメントをもとにLambda開発環境を構築する
[Quick Start - AWS Serverless Application Model](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-quick-start.html)

いったんsample用のディレクトリを作って移動する

```
mkdir sam_sample && cd sam_sample
```

QuickStartではPythonで書いてるけど、Rubyで構築してみる[Building Lambda Functions with Ruby - AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-ruby.html)

## 初期化

Rubyでsamプロジェクトを初期化するとsam-appというディレクトリが作られてlambdaのテンプレートなるファイルが作られた 

```
sam init --runtime ruby2.5
```

Gemfileに[httparty](https://github.com/jnunemaker/httparty)という全然知らないhttp clientがある

```
cd sam-app
sam_sample/sam-app » sam build --use-container
2019-01-10 20:39:56 Starting Build inside a container
2019-01-10 20:39:56 Found credentials in shared credentials file: ~/.aws/credentials
2019-01-10 20:39:56 Building resource 'HelloWorldFunction'

# aws-cliでアクセストークンやシークレットキー、リージョンの設定を入力していないとエラーになる
```

*ビルドする際に sam build --use-container を使うとAWSのLambdaが実際に動いている環境に近いコンテナで実行してくれるとかなんとか書いてあるが、オプション無しでも実行時にDockerを使うので正直ようわからん*

### ローカル起動

#### API Gatewayで起動

[Running API Gateway Locally - AWS Serverless Application Model](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-using-start-api.html)を参考に実行

```
sam local start-api
```

ブラウザで下記にアクセス
http://127.0.0.1:3000/hello

```
{
"message": "Hello World!",
"location": "175.131.178.24\n"
}
```

#### 単独で起動

[Invoking Functions Locally - AWS Serverless Application Model](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-using-invoke.html)を参考に実行

sam-app下にあるtemplate.yamlファイルを見ると、
Resourcesの直下のキー 'HelloWorldFunction' が一つ一つのLambdaファンクションの設定となっている

```
Resources:
    HelloWorldFunction:
        Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
        Properties:
            CodeUri: hello_world/
            Handler: app.lambda_handler
            Runtime: ruby2.5

```


標準入力からからのオブジェクトを渡して起動してあげる

```
echo "{}" | sam local invoke "HelloWorldFunction"

START RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72 Version: $LATEST
END RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72
REPORT RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72	Duration: 656.91 ms	Billed Duration: 700 ms	Memory Size: 128 MB	Max Memory Used: 29 MB
{"statusCode":200,"body":"{\"message\":\"Hello World!\",\"location\":\"175.131.178.24\\n\"}"}
```

timeコマンドで測ってみると6.5秒ほどかかる。結構遅い。
`sam build`した際に`--use-container`を付けても付けなくても遅い。次で説明するテストコードを実行することでサクサクっと開発してある程度作ったら確認するのが良さそうだ

template.yml にcloudformationみたいな(同じ？)設定がありAPI GatewayでLambdaが呼び出されるようになっている


## テスト実行方法

### テスト実行で使うgemのインストール

```
gem install mocha
```

これ以外にもLambda本体で利用するgemのインストールする必要がある。

```
gem install httparty
```

### rubyコマンドでテストを実行する

テストの内容は

```
ruby tests/unit/test_handler.rb

Loaded suite tests/unit/test_handler
Started
.
Finished in 0.001067 seconds.
-------------------------------------------------------------------------------------------------------
1 tests, 4 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------------------
937.21 tests/s, 3748.83 assertions/s
```

こちらは爆速である。デフォルトで設定されているテストはlambda_handlerで必要なeventのモックと、lambda内で通信するモックをつくり想定したレスポンスをlambda_handlerで返しているかどうか見ている。フィーチャーテストっぽい。


## まとめ

*　aws samの環境構築から、ローカル実行、テストの実行までできた
*　最近できたRubyでlambdaを動かせた

今後の課題

* samを使ってローカル開発する場合の最小のIAMユーザの権限はなにか、またAWSにデプロイする際に必要な権限はなにか調査
* Lambdaが実行時にS3をファイルに置くよような場合のIAMはどこで設定するのか調査
* 開発、テスト、デプロイ、運用のライフサイクルを検討する。コマンドでデプロイではなくGithubでマージされたらデプロイするなど実運用を想定して検証
* aws sam環境をDockerでコンテナにしてローカル開発環境を作れないか検討


参考情報

[Installing the AWS SAM CLI - AWS Serverless Application Model](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)

[AWS Command Line Interface をインストールする - AWS Command Line Interface](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html)

[AWS SAM で Hello World する - Qiita](https://qiita.com/mokuo/items/3348f19d12cb9b17295d)
[ローカルで TypeScript + AWS SAM (Lambda/DynamoDB) の開発環境を構築する - Qiita](https://qiita.com/navitime_tech/items/70432345d930c2bc1a14)
[aws-sam-localだって!?これは試さざるを得ない! - Qiita](https://qiita.com/DeployCat/items/0e631029ae4ef41c0f3f)
[Lambda 関数のビルド - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-app.html)
[デプロイパッケージの作成 - AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/deployment-package-v2.html)