Zappaでサーバーレスアプリケーションを作成するための最初の1歩

[近畿大学 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kindai)の8日目を担当することになり、QiitaではCSGの夏のAdventCalendar以来、2つ目の投稿になります。今回は、Zappaってのを使うと気軽にAWS Lambdaベースのサーバーレスアプリケーションを運用できるぞというお話です。学生向けに書いてますので、話が逸れるところが少しありますがご了承ください。

### サーバーレスアプリケーションとは
一昔前までは、ウェブアプリケーションのようなクライアント・サーバ型のアプリケーションを開発するときは、サーバマシンというものが必要で、さらにその中でサーバプログラムを動かすために、例えばApacheのようなウェブサーバや、TomcatのようなJava Servletコンテナと呼ばれるミドルウェアを設定してするのが一般的でした（ちょっとネタが古い？）。
サーバーレスアプリケーションとは（サーバーレスコンピューティングとも言いますね）、そういったサーバーのインフラ整備を一切気にすることなく、プログラムを放り込めばすぐ稼働するようなプラットフォーム上で動くアプリケーションのことです。サーバーがないというわけではありません。GoogleのGAE（Google App Engine）がそのハシリになるのでしょうか。

### Lambdaとは
[Lambda](https://aws.amazon.com/jp/lambda/)とは、まさにサーバーレスアプリケーションを実現するPaaS（Platform as a Service ）で、AWSのサービスの１つです。Node.js、Python、Ruby、Java、Go、C#といった言語に対応しており、様々なトリガーに応じてコードを実行させることができます。正確に言うと、Lambda上のコードをウェブアプリケーションとして動かすためには、AWS API Gatewayと呼ばれるサービスと連携させる必要があります。よって、Lambdaでサーバーレスアプリケーションを実現するには、ある程度AWSが提供するサービスの仕組みを理解しておく必要があります。Lambdaの料金体系は基本的にコードを実行した分だけにかかります。動かさなければ料金は発生ぜず（S3にコード類を保存するのでその料金はかかります）、無料枠（1,000,000 リクエスト/月）もあるというところが個人的にLambda推しですね。

###Zappaとは？
Pythonには幾つかのウェブアプリケーションフレームワークが存在しますが、その１つに[Flask](https://www.fullstackpython.com/flask.html)があります。Flaskは最小限の機能に限定した軽量なフレームワークとされていますが、Jinja2と呼ばれるテンプレートエンジンを標準で利用できるので、Flaskはちょっとしたアプリケーションに適しています。

 そして本題の[Zappa](https://github.com/Miserlou/Zappa)とは、AWSのLambdaやAPI Gateway等のサービスを利用してFlask ベースのサーバーレスアプリケーションを実現するフレームワークです。Zappaを用いると、LambdaとAPI Gatewayとを連携させる部分の記述を気にすることがなくなるという利点があります。

ということで、Zappaでサクサク開発～と言いたいところなんですが、ノー知識で手を出すと環境整備で苦労しますので、最低限の情報とキーワードを挙げていきます。不明なキーワードは自分で調べてみてください。

### まずはAWSの設定
AWSを利用するわけですから、最低限の環境設定が必要です。するべき事を下記に書きます。わからなければ他を調べてください。
(1) AWSを利用できるようユーザ登録（サインアップ）しておく（大大大前提ですね）
(2) IAMを利用してLambdaやAPI Gatewayを利用するアカウントを作成。AWSのサービスを利用するときは、それ用のアカウントをIAMと呼ばれる管理ツールを利用して作成する必要があります（AWSのウェブ管理画面からアクセスできます）。作成したらAccess Key ID、Secret Access Keyなどをメモっておきましょう。
(3) aws-cliをインストール。AWSのサービスの設定は基本はウェブ上でやりますが、これはAWSのサービスをコマンドラインで操作するためのツール群です。ZappaはAPI GatewayとLambdaの連携を自動化してくれますが、内部的にはaws-cliを利用しているってことですね。
(4) aws configureを実行する。これはaws-cliを利用するための初期設定です。上述で取得したAccess Key IDやSecret Access Keyなどを入れる他に、region name、output formatを設定する必要があります。

##### （補足）IAMでのアカウントのロール設定について
これについての情報が非常に少なく、もしかしたら私が勘違いしているのかもしれませんが、IAMで作成したアカウントに対して、LambdaとかAPIGatewayなどをアクセスする権限（ロール）の設定が必要です。このあたりの設定が不十分だと、zappa でのデプロイ時に権限がらみのエラーが出ます。zappaもしかしたら私が勘違いしているのかもしれませんが、IAMで作成したアカウントに対して、LambdaとかAPIGatewayなどをアクセスする権限（ロール）の設定が必要です。このあたりの設定が不十分だと、zappa でのデプロイ時に権限がらみのエラーが出ます。zappaが自動的に設定してくれてそうな気がしたのですが、なぜかうまくいかなかったので、その場合は、とりあえず下記のロールを追加しておくとエラーはでないでしょう。

 - AWSLambdaFullAccess
 - IAMFullAccess
 - AWSLambdaDynamoDBExecutionRole
 - AmazonAPIGatewayAdministrator
 - AWSCodeDeployRoleForLambda
 - AWSLambdaExecute
 - AWSCloudFormationFullAccess

以上で、AWS周りはOKかな。。

### Zappaのインストール
と、その前に、、、zappa は virtualenv を前提に動作するようなので、pythonでvirtual environmentを作ってその環境でインストールしましょう。なお、私の場合、Anaconda（GUI）で仮想環境作りましたが、その環境下でもOKでした。zappaのインストールは以下の通り。

```shell
$ pip install flask
$ pip install zappa
```

#### 初期設定ファイルを作成
Zappa init で初期設定ファイルを作ります

```
$ zappa init
```

このコマンドを実行することで、zappa_settings.js というファイルができます。

#### zappa init でのエラー
以下のようなエラー出たときの対処法を書いておきます。
```エラー：zappa init error: "Zappa requires an active virtual environment
```→　環境変数でVIRTUAL_ENV を設定してください。

```エラー：zappa Init error 'utf8' codec can't decode byte 0x**
```→　このエラーは単にディレクトリの場所（or 権限の？）問題だけのようです。（自分がこれから作成しようとしている）Pythonのプロジェクトファイルのフォルダに移動してみてから initを再度実行してみてください。

#### zappa_settings.jsonファイルについて
zappa コマンドは、このファイルに記述されている情報に従ってプロジェクトをデプロイします。必要に応じてファイルを修正しましょう。ここの肝は、project_nameという変数を変えることで、別プロジェクトのような扱いになります。つまり異なるLambda関数となり、APIGatewayでのURLも変わることになります。また、app_functionのパラメーターで、実行するメインプログラムのファイルを決めるようです。

```json:zappa_settings.json
{
    "dev": {
        "app_function": "test.app", 
        "profile_name": "default",  ←AWSのプロファイル
        "project_name": "test-app7", 
        "aws_region": "us-east-1",
        "runtime": "python3.7",
        "apigateway_enabled": true,
        "s3_bucket": "*******" ←適切な名前に変えてください
    }
}
```

#### サンプルコード
出力するHTMLファイル。ファイルの場所はtemplete以下に置きますので注意。

```html:template/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HELLO</title>
</head>
<body>
    <p>Merry Christmas</p>
</body>
</html>
```

Pythonのコード

```python:test.py
from flask import Flask, render_template
app = Flask(__name__)
 
@app.route('/')
def hello():
    html = render_template('index.html')
    return html
 
if __name__ == "__main__":
    app.run()
```

なお、つまらないサンプルでスミマセン。。。

#### zappaコマンド（デプロイ、更新、削除）
上記のファイルを準備できたら、あとの操作は下記のようになります。

```
（はじめてプロジェクトをデプロイする場合）
$ zappa deploy dev
（更新する場合）
$ zappa update dev
（削除する場合）
$zappa undeploy dev
```
実行すると、URLが出てきますのでそこにアクセスすれば実行できると思います。

さて、どうでしょう？上述の一歩を踏み出せば、あとはアプリ実装するだけです。お手軽に公開できるのでぜひお試しください！