サーバーレスアプリケーションを管理する(SERVER LESS)

# 前置き
だんだんと Lambda function が増えてきたので管理してみようと思いました。今回は [Serverless](https://serverless.com/framework/docs/) を使ってみます。

# インストール
ますはインストールします。

## 事前準備
以下をインストールします。

- [nvm](https://github.com/creationix/nvm)
- node


## Serverless framework をインストール
[この記事](http://dev.classmethod.jp/server-side/serverless-framework-practices/#toc-serverless) を参考に、各プロジェクトごとにインストールをします。

```package.json
{
  "name": "project-name",
  "devDependencies": {
    "serverless": "^1.16.0"
  },
  "scripts": {
    "sls": "serverless"
  }
}
```

### エラーが出るとき
インストールしたときに怒られちゃいました・・・

>Error: Cannot find module '/path/to/project/node_modules/serverless/node_modules/tabtab/src/cli.js'

[issue](https://github.com/serverless/serverless/issues/3792)を参考に、オプションをつけて再度インストールしたところ成功！
無事インストールが完了しました！

```
$ sls --version
1.16.0
```

# サービスを作成する
Serverless framework では、サーバーレスアプリケーションを service という単位で切り分けるようです。
まずは Serverless framework が提供しているテンプレートを利用して作成してみまんす。

```
$ sls create --help
Plugin: Create
create ........................ Create new Serverless service
    --template / -t (required) ......... Template for the service. Available templates: "aws-nodejs", "aws-python", "aws-python3", "aws-groovy-gradle", "aws-java-maven", "aws-java-gradle", "aws-scala-sbt", "aws-csharp", "azure-nodejs", "openwhisk-nodejs", "openwhisk-python", "openwhisk-swift", "google-nodejs", "plugin" and "hello-world"
    --path / -p ........................ The path where the service should be created (e.g. --path my-service)
    --name / -n ........................ Name for the service. Overwrites the default name of the created service.
```

ふむふむ、テンプレートがたくさん良いされてますな。今回は AWS Lambda で python3 なので、 `aws-python3` を選択します。

```
$ sls create -t aws-python3 -p service
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/path/to/project/service"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.16.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"
```

でけた！ファイルが何個かできてますね。

```
ls -la srvice
total 24
drwxr-xr-x  5 user  staff   170  6 22 10:50 .
drwxr-xr-x  6 user  staff   204  6 22 10:47 ..
-rw-r--r--  1 user  staff   192  6 22 10:47 .gitignore
-rw-r--r--  1 user  staff   490  6 22 10:47 handler.py
-rw-r--r--  1 user  staff  2787  6 22 10:47 serverless.yml
```

何ができるのかな？

```
$ sls

Commands
* Serverless documentation: http://docs.serverless.com
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--help" after any <command> for contextual help

config ........................ Configure Serverless
config credentials ............ Configures a new provider profile for the Serverless Framework
create ........................ Create new Serverless service
install ....................... Install a Serverless service from GitHub
package ....................... Packages a Serverless service
deploy ........................ Deploy a Serverless service
deploy function ............... Deploy a single function from the service
deploy list ................... List deployed version of your Serverless Service
deploy list functions ......... List all the deployed functions and their versions
invoke ........................ Invoke a deployed function
invoke local .................. Invoke function locally
info .......................... Display information about the service
logs .......................... Output the logs of a deployed function
login ......................... Login or sign up for the Serverless Platform
logout ........................ Logout from the Serverless Platform
metrics ....................... Show metrics for a specific function
remove ........................ Remove Serverless service and all resources
rollback ...................... Rollback the Serverless service to a specific deployment
rollback function ............. Rollback the function to a specific version
slstats ....................... Enable or disable stats

Plugins
AwsCommon, AwsCompileAlexaSkillEvents, AwsCompileApigEvents, AwsCompileCloudWatchEventEvents, AwsCompileCloudWatchLogEvents, AwsCompileCognitoUserPoolEvents, AwsCompileFunctions, AwsCompileIoTEvents, AwsCompileS3Events, AwsCompileSNSEvents, AwsCompileScheduledEvents, AwsCompileStreamEvents, AwsConfigCredentials, AwsDeploy, AwsDeployFunction, AwsDeployList, AwsInfo, AwsInvoke, AwsInvokeLocal, AwsLogs, AwsMetrics, AwsPackage, AwsProvider, AwsRemove, AwsRollback, AwsRollbackFunction, Config, Create, Deploy, Info, Install, Invoke, Login, Login, Logs, Metrics, Package, Platform, Remove, Rollback, SlStats
```

お、ローカルでのテスト用コマンドもあるみたいですね。試してみましょ。


# テスト
まずはテンプレートで作成されたファンクションをテストしてみまんす。


```
$ cd service
$ sls invoke local -f hello
```

すると・・・

>Error: spawn python3.6 ENOENT

まーた怒られちゃいました・・・どうやらローカル環境のpythonが3.6じゃないようですね。
pyenv　と pyenv-virtualenv で解決しました！


# デプロイ
では実際にAWSへデプロイしてみます！

### その前に
デプロイの前にAWSのクレデンシャル設定をします。

```
$ aws configure
```

すでに複数のクレデンシャルを管理している場合は

```
$ export AWS_PROFILE="profileName" && export AWS_REGION=ap-northeast-1
```

で[いけます！](https://serverless.com/framework/docs/providers/aws/guide/credentials/#using-aws-profiles)


### デプロイ！
これを実行するだけ！

```
$ sls deploy
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: dev
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: function

```

AWSコンソールでLambdaを確認すると・・・できてました！

# Tips
### 環境でリソースを使い分ける
今回はテストコードでしたが、実際はステージングや本番で同じコードを利用した運用がしたいと思います。
例えば・・・
>DB更新したいからVPCにLambdaをおきたいけど、ステージングと本番でVPCわけちゃってるやー

こんな時、デプロイの設定で配置するVPCがわけられたら素敵ですよね！そんな時はこうします！

```
18 # ステージによって使い分けたい設定を記述
19 custom:
26   vpc:
27     staging:
28       securityGroupIds:
29         - sg-sgsgsgsg
30       subnetIds:
31         - subnet-aaaaaaaa
32         - subnet-cccccccc
33 
34 provider:
35   # ステージの値をデプロイ時のパラメータで上書き（デフォルトはdev）
37   stage: ${opt:stage, self:custom.defaultStage}
38   # ステージの値を利用して値を使い分ける
42   vpc: ${self:custom.vpc.${self:provider.stage}}
```
こんな感じでserverless.ymlに設定します。

あとはデプロイコマンドにパラメータを追加すればOK!

```
$ sls deploy --stage staging
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (1.35 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: service
stage: staging
region: ap-northeast-1
api keys:
  None
endpoints:
  None
functions:
  update: function

```

stageが前回はdevでしたが、今回はstagingに変わってますね！この仕組みを利用すれば環境変数などもステージにより使い分けることができますので、より捗ります！


# 最後に
バージョン管理からデプロイまで管理できることにより、非常にサーバーレスヘの敷居が低くなりました。サーバレスアプリケーションは開発が簡単な分、運用への意識が低くなり、どうしても「今ってどのバージョンが動いてるんだっけ？」「これっていつ誰が作ったの？」など、逆にコストがかかることもありましたが、サーバーレスフレームワークを利用することにより、今までと変わらない開発、テスト、運用が適用できるようになりますね！