Serverless FrameworkでAWS Lambda関数を作成する

## 概要
Serverless Frameworkとは、Lambda、API Gateway、DynamoDBなどを作成、管理、デプロイできるツールです。
Frameworkと付いていますが、ツールです。
この記事では、python3でLambda関数を作成します。

## 環境
- CentOS 7.2
- serverless 1.23.0
- node v6.11.3
- npm 3.10.10
- OpenSSL 1.0.2k-fips  26 Jan 2017


## npmのインストール
以下の記事を参照
[npmのインストール手順](https://qiita.com/Esfahan/items/067fc366d6a6e7b8690d)


## Serverless Frameworkのインストール
slsというディレクトリを作成し、そこで作業を行います。

```
$ mkdir sls
$ cd sls
$ npm init
```

```
$ npm install --save serverless
```

serverlessコマンドのパスを通します

```
$ npm bin serverless
$ echo 'export PATH="$HOME/sls/node_modules/.bin/:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile
```

インストール確認

```
$ serverless -v
1.23.0
```

## aws credential登録
以下のコマンドで、AWSのキーを登録します。

```
$ serverless config credentials --provider aws --key XXXXXXXXXXXXEXAMPLE --secret XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEXAMPLEKEY
Serverless: Setting up AWS...
Serverless: Saving your AWS profile in "~/.aws/credentials"...
Serverless: Success! Your AWS access keys were stored under the "default" profile.
```

## Lambda関数の作成
以下のコマンドで、Lambda関数を作成します。

```
$ serverless create -t aws-python3 -p sample-app

Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/home/vagrant/sls/sample-app"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.23.0
 -------'

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

オプションの説明ですが、
`-p`は、Lambda関数名のprefixとなります。

また、`-t`で実装する言語を選びます。
以下のいずれかを選択します。

- -t
   - aws-nodejs
   - aws-python
   - aws-python3
   - aws-java-maven
   - aws-java-gradle
   - aws-scala-sbt
   - aws-csharp
   - openwhisk-nodejs

すると、以下のファイルが生成されます。
handler.pyは、Lambda関数のテンプレート、serverless.ymlは設定ファイルになります。

```
$ ll sample-app/
total 8
-rw-rw-r--. 1 vagrant vagrant  497 Oct 10 04:42 handler.py
-rw-rw-r--. 1 vagrant vagrant 2758 Oct 10 04:42 serverless.yml
```

## 関数の情報を設定
serverless.ymlに関数の設定情報が書かれているので、環境合わせて編集します。


```diff:serverless.yml
provider:
  name: aws
  runtime: python3.6
+  # 実行時間上限のdefaultが6秒のため、必要に応じて変更、以下はmaxの300秒
+  timeout: 300
+  # 必要なポリシーをアタッチする
+  iamRoleStatements:
+    - Effect: "Allow"
+      Action:
+        - "ec2:CreateSnapshot"
+        - "ec2:DeleteSnapshot"
+        - "ec2:DescribeSnapshots"
+        - "ec2:DescribeInstances"
+        - "ec2:DescribeVolumes"
+      Resource:
+        - "*"

# you can overwrite defaults here
- # stage: dev
- # region: us-east-1
+  stage: production
+  region: ap-northeast-1

# *snip*

# 関数名などの定義
functions:
-  hello:
-    handler: handler.hello
+  sample-func:
+    handler: handler.main
+    # Cloudwatchをtriggerにして定期実行する場合はこんな感じ
+    events:
+      # UTCで書く
+      - schedule: cron(0 19 * * ? *)
```

このファイルで、IAMロールやcloudwatchの設定を書くことで、自動でそれぞれ作成されるようになります。


serverless.ymlで、関数のメソッド名を変更したので、handler.pyも以下のように編集します。

```diff:handler.py
-def hello(event, context):
+def main(event, context):
```

## deploy
以下のコマンドでデプロイをします。

```
$ cd sample-app
$ serverless deploy

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (389 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: sample-app
stage: production
region: ap-northeast-1
stack: sample-app-production
api keys:
  None
endpoints:
  None
functions:
  sample-func: sample-app-production-sample-func
```

すると、`sample-app-production-sample-func`という名前のLambda関数が作成されます。

## Lambda関数の実行
deployが出来たら、以下のコマンドで、Lambda関数を実行することができます。

```
$ serverless invoke -f sample-func

{
    "statusCode": 200,
    "body": "{\"message\": \"Go Serverless v1.0! Your function executed successfully!\", \"input\": {}}"
}
```

パラメータを付ける場合は、`-d`オプションで指定します。
戻り値にinputの項目が増えているのが確認できます。

```
$ serverless invoke -f sample-func -d '{"key":"value"}'

{
    "statusCode": 200,
    "body": "{\"message\": \"Go Serverless v1.0! Your function executed successfully!\", \"input\": {\"key\": \"value\"}}"
}
```

以下のようなjsonファイルを作成して、パラメータを渡すこともできます。

```json:event.json
{
  "key" : "value"
}
```

`-p`オプションでjsonファイルを指定して実行

```
$ serverless invoke -f sample-func -p event.json
{
    "statusCode": 200,
    "body": "{\"message\": \"Go Serverless v1.0! Your function executed successfully!\", \"input\": {\"key\": \"value\"}}"
}
```

## logを確認
以下のコマンドで確認できます。

```
$ serverless logs -f rotate-snapshots
```

## Lambda関数の削除
関数の削除は以下のコマンドで行います。
関連するS3のファイルもすべて消してくれます。
AWS Console上で手動でLambda関数を削除すると、S3のファイルなどが残ってしまいます。


関数のあるディレクトリに移動でして実行します。

```
$ cd sample-function
$ serverless remove -v
```

`-s`オプションで、特定のstageのみを削除することもできます。

```
$ serverless remove -v -s dev
```

## その他
以下のモジュールで、擬似的にローカルでApi Gateway、DynamoDBを使うことができます。

```
$ npm install aws-sdk
# 擬似的Api Gateway
$ npm install --save-dev serverless-offline
# 擬似的DynamoDB
$ npm install --save-dev serverless-dynamodb-local
```

## pipモジュールを使う場合
pythonで開発していて、pipのモジュールを使う場合に必要な設定

### serverless-python-requirementsをインストール

```
$ npm install --save serverless-python-requirements
```

### serverless.ymlに追記

```diff:serverless.yml
provider:
  name: aws
  runtime: python3.6
  timeout: 300

# you can overwrite defaults here
  stage: production
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "ec2:CreateSnapshot"
        - "ec2:DeleteSnapshot"
        - "ec2:DescribeSnapshots"
        - "ec2:DescribeInstances"
        - "ec2:DescribeVolumes"
      Resource:
        - "*"

+plugins:
+  - serverless-python-requirements
```

### requirements.txtを作成

```
$ pip freeze > requirements.txt
```

### deploy

```
$ serverless deploy
```

## 参考
- [今から始めるServerless Frameworkで簡単Lambda開発環境の構築](https://dev.classmethod.jp/cloud/aws/easy-deploy-of-lambda-with-serverless-framework/)
- [Serverless アプリケーションをローカルで開発する](https://qiita.com/noralife/items/e36621ddd0e5b8ff4447)
- [とことんサーバーレス①：Serverless Framework入門編](https://qiita.com/hiroshik1985/items/6d979ff1afb56953b62e)
- https://github.com/serverless/serverless
- [Serverless Frameworkのプラグインを利用した外部モジュールの管理](https://dev.classmethod.jp/cloud/aws/managing-external-modules-with-serverless-framework-plugin/)