Serverless Frameworkを使ったLambda開発

以前に[AWS SAMを使ったLambda開発](https://qiita.com/nakahara-d/items/1b861ea61dbbffaf90b8)をしてみましたが、今回はAWS SAMと比較しつつ、Serverless Frameworkを使ったLambda開発を試してみます！

# Serverless Frameworkとは

[Serverless Framework](https://www.serverless.com/)はAWS、Azure、GCPなどマルチクラウドに対応したサーバーレスアプリケーション開発フレームワークです。

オープンソース版とPro版があり、Pro版ではCI/CDやモニタリングの機能が使えますが、今回はオープンソース版を試してみます。

# 準備

## Serverless Frameworkのインストール

Serverless Frameworkをインストールします。
スタンドアロンバイナリとnpmでインストールできるようですが、今回はnpmでインストール。
後述するプラグインでもnpmを使ったりするので、Node.jsの環境は用意しておいた方が良さそうです。

https://www.serverless.com/framework/docs/getting-started/

```bash
npm install -g serverless
```

## 認証情報を設定する

Serverless Frameworkで使用する認証情報を設定しておきます。
AWSで使用する場合は以下を参考に。

https://www.serverless.com/framework/docs/providers/aws/guide/credentials/

本番/ステージングで使用する環境は異なると思うので、AWS CLIを使ってプロファイルを作成しておき、`serverless deploy --aws-profile [Profile]`で指定するか、`serverless.yml`で設定するのが良さそう。どこにも設定がないとAWS CLIのデフォルト認証が使用されるので注意！

# テンプレートをダウンロード

`AWS - Python - Starter`を見てみます。

```bash
$ serverless

 What do you want to make? AWS - Python - Starter
 What do you want to call this project? aws-python-project

Downloading "aws-python" template...

Project successfully created in aws-python-project folder

You are not logged in or you do not have a Serverless account.

 Do you want to login/register to Serverless Dashboard? No

 Do you want to deploy your project? No

Your project is ready for deployment and available in ./aws-python-project

  Run serverless deploy in the project directory
    Deploy your newly created service

  Run serverless info in the project directory after deployment
    View your endpoints and services

  Run serverless invoke and serverless logs in the project directory after deployment
    Invoke your functions directly and view the logs

  Run serverless in the project directory
    Add metrics, alerts, and a log explorer, by enabling the dashboard functionality
```

テンプレートで作られるファイルはかなりシンプル。

```
aws-python-project/
├── README.md
├── handler.py
└── serverless.yml
```

## handler.py

単純なHTTPレスポンスを返すだけ。

```python
import json


def hello(event, context):
    body = {
        "message": "Go Serverless v2.0! Your function executed successfully!",
        "input": event,
    }

    return {"statusCode": 200, "body": json.dumps(body)}
```


## serverless.yml

最低限の設定のみという感じ。

```yaml
service: aws-python-project

frameworkVersion: '2'


provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221

functions:
  hello:
    handler: handler.hello
```

デプロイのプロファイルやリージョンの設定を`serverless.yml`ファイルで設定できるようです。

https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/


# ローカルテスト

```bash
$ serverless invoke local --function hello
{
    "statusCode": 200,
    "body": "{\"message\": \"Go Serverless v2.0! Your function executed successfully!\", \"input\": {}}"
}
```

レスポンスが確認できます。


`--docker`オプションを付けるとAWS SAMと同様にdockerを使ってLambda環境を再現して実行できます。

```bash
$ serverless invoke local --function hello --docker
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Downloading base Docker image...
Serverless: Writing Dockerfile...
Serverless: Building Docker image...
START RequestId: df3eb7b9-2565-1436-ffc9-4b7504a0a6c8 Version: $LATEST
END RequestId: df3eb7b9-2565-1436-ffc9-4b7504a0a6c8
REPORT RequestId: df3eb7b9-2565-1436-ffc9-4b7504a0a6c8  Init Duration: 115.71 ms        Duration: 3.05 ms       Billed Duration: 4 ms   Memory Size: 1024 MB    Max Memory Used: 29 MB

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


ちなみに使用されるDockerイメージはこちら。

https://github.com/lambci/docker-lambda

# デプロイ

```bash
$ serverless deploy --region ap-northeast-1
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 aws-python-project.zip file to S3 (2.24 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
Service Information
service: aws-python-project
stage: dev
region: ap-northeast-1
stack: aws-python-project-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: aws-python-project-dev-hello
layers:
  None
```

デプロイ時のオプションでもプロファイルやリージョンの設定ができます。

https://www.serverless.com/framework/docs/providers/aws/cli-reference/deploy/

Serverless FrameworkでもAWS SAMと同様にCloud Formationでデプロイが行われます。
AWS SAMと異なりアプリケーションごとにLambdaをアップロードするS3バケットが作られるようです。

今回のケースでは`aws-python-project-dev`というスタックで、S3バケットとLambdaが作られていました。

# プラグイン

AWS SAMにはないServerless Frameworkの目玉機能な気がします。
JavaScriptで書かれたコードでServerless Frameworkに新しいコマンドを追加したり、既存のコマンドの処理を拡張したりできます。

現時点で1000以上のプラグインが公開されているようですが、Serverless自体がAWS Lambda向けの開発から始まっているためか多くはAWS Lambda向けのものとなっています。

https://www.serverless.com/plugins/

便利そうなプラグインをいくつか列挙しておきます。

## Serverless Python Requirements

https://www.serverless.com/plugins/serverless-python-requirements/

デプロイする際に`requiremets.txt`を読み込んで、依存する外部モジュールをバンドルする。
Pythonでパッケージ依存関係がある場合は必須。`requiremets.txt`だけでなくPipenv、Poetryにも対応してるのも良い！！

## Serverless Offline

https://www.serverless.com/plugins/serverless-offline

LambdaとAPI Gatewayをエミュレートするコマンドを追加する。
ローカルで簡単にHTTPリクエストを投げてテストできる。


# まとめ

細かい動作に違いはありましたが、基本的なことする分にはServerless FrameworkとAWS SAMどちらを使ってもあまり変わりないかなという印象でした。
ただServerless Frameworkにはマルチクラウド、プラグインといった特徴があり、これを生かすことができる環境であればかなり有力な選択肢になるのではないでしょうか。