Docker+Zappa+Flask+AWSでサーバーレスWebアプリ構築を手軽に体験する

電子書籍 本田崇智著 [Pythonで作るはじめてのサーバレスアプリケーション Kindle版](https://www.amazon.co.jp/dp/B07JD6NDS7)（以降、書籍）を参考に、書籍内で紹介されている手順を一部アレンジしつつ、Flaskを利用したサーバーレスWebアプリのサンプルをAWSに構築した際の手順メモ。

- 本記事では、書籍内の章構成のうち「PipEnvの導入」章から「サーバレスアプリケーションを導入する」章までの手順をトレースしつつ、サーバーレスWebアプリの構築を手軽に素早く行えるようアレンジした手順を紹介している。
- 本記事の手順中で書籍の参照を必要とする項目があるため、Kindleで書籍を購入済みであることを前提とする。なお、書籍はKindle Unlimited対象本(2019/6/1現在)である。
- Macのマシン環境を汚さないように、コード作成からZappaによるAWSへのデプロイまでをDockerコンテナ上で完結させている。（書籍のオリジナルの手順ではMacローカル上に直接環境を作成している）
- 書籍の著者がGithubで公開している書籍向けのサンプルコードをgit cloneし、コード作成を省略している。（書籍のオリジナルの手順ではひとつひとつのコードを解説しながら作成している）
- PynamoDBによるローカルでのWebアプリ動作確認は省略している。

2019/6/19更新：
Zappa、Flalsk、PynamoDBに対する理解が少し深まったため、手順を大きく見直した。（見直し前の手順は記事末尾に残してあります。）

# 環境

- OSX 10.13.6
- Docker Desktop for Mac 2.0.0.3
- Amazon Web Services（リージョン：ap-northeast-1）

# 手順

### AWS IAMの作成

1.「AWS IAMの作成」章（書籍内60%位置付近）を参考に、アプリ(Lambda関数)がDynamoDBにアクセスするためのAWS IAMを作成。
2.「zappa用のAWS IAMの作成」章（書籍内65%位置付近）を参考に、ZappaがDocker上からAWSにアプリをデプロイするためのAWS IAMを作成。

### MAC上のターミナルでDockerコンテナの作成

3.Python3.6の公式イメージを利用してコンテナを作成、ログイン

```shell
$ docker run -it python:3.6 /bin/bash
```

### Dockerコンテナ上のbashでコード作成、デプロイ

4.サンプルコードをダウンロード 

```shell
$ git clone https://github.com/chaingng/serverless_python_tutorial.git
```

5.applicationフォルダに移動 

```shell
$ cd serverless_python_tutorial/application
```

6.Pipenvのインストール。Zappaを利用するのに仮想環境が必要 

```shell
$ pip install pipenv
```

7.Python3仮想環境の初期化 

```shell
$ pipenv --three
```

8.Pipenvシェル有効化 

```shell
$ pipenv shell
```

9.Pipfileに記載のパッケージをインストール 

```shell
$ pipenv install
```

10.AWS CLIをインストール 

```shell
$ pipenv install awscli
```

11.AWS CLIプロファイルを作成

```
$ aws configure
```

上記コマンドを実行すると対話式で入力を求められるので以下のように入力。

```
AWS Access Key ID [None]: [項番2で作成したIAMアクセスキーID]
AWS Secret Access Key [None]: [項番2で作成したIAMシークレットアクセスキー]
Default region name [None]: ap-northeast-1
Default output format [None]: #Enter押下
```

12.環境変数の設定。

```shell
$ export SERVERLESS_BLOG_CONFIG=production
```

13.DynamoDBテーブルの作成

```shell
$ python manage.py init_db
```

14.変数の指定

```shell
$ SERVERLESS_USER=[本番環境でのユーザーログインパスワード(任意の文字列)]
$ SERVERLESS_SECRET_KEY=[本番環境でのsecret(任意の文字列)]
$ SERVERLESS_AWS_ACCESS_KEY_ID=[項番1で作成したIAMアクセスキーID]
$ SERVERLESS_AWS_SECRET_KEY=[項番1で作成したIAMシークレットアクセスキー]
```

15.Zappa設定ファイルを編集

```shell
$ cat << EOF > zappa_settings.json
{
    "dev": {
        "app_function": "server.app",
        "aws_region": "ap-northeast-1",
        "project_name": "application",
        "runtime": "python3.6",
        "s3_bucket": "serverless-blog-bucket-$RANDOM"
        "environment_variables": {
            "SERVERLESS_BLOG_CONFIG":"production",
            "SERVERLESS_USER_PW":"${SERVERLESS_USER}",
            "SERVERLESS_SECRET_KEY":"${SERVERLESS_SECRET_KEY}",
            "SERVERLESS_AWS_ACCESS_KEY_ID":"${SERVERLESS_AWS_ACCESS_KEY_ID}",
            "SERVERLESS_AWS_SECRERT_KEY":"${SERVERLESS_AWS_SECRET_KEY}"
        }
    }
}
EOF
```

16.Docker上のコードをAWSへデプロイ

```shell
$ zappa deploy
```
    
# 動作確認

前項13の実行結果に表示されるURL`https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev`にブラウザでアクセス。

アクセスできた。
ユーザ名（john）とパスワード（本番環境でのユーザーログインパスワード）でログインしてみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/82fd43af-5706-c386-0fca-4ebf424b920c.png" width="500px">

ログインできた。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/7f3081dd-7fd0-7e24-b410-0286b02110d9.png" width="500px">

新規投稿してみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/26533329-ebc6-7c99-dac5-97b0caf23b7b.png" width="500px">

新規投稿できた。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/a308aa6e-b81c-07d5-3fa1-bd0639957cf0.png" width="500px">

続きを読んで見る。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/e58a29c5-eb4b-afd7-b1ef-7b149cf93eca.png" width="500px">

編集してみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/5b6c62cc-c06d-7632-ef54-bc2362bf37ea.png" width="500px">

編集できた。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/82dd268c-0983-e66d-ddc5-bed65c91d0bf.png" width="500px">

# 後始末

デプロイしたWebアプリをAWS上から削除したい場合は、以下を実行

```
$ zappa undeploy dev
```

S3バケットはundeployコマンドで削除されないため、下記より手動で削除
https://s3.console.aws.amazon.com/s3/home

2019/6/8追記：
Lambda実行用のIAMも自動で削除されないため、下記より手動で削除
https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/roles

2019/6/19追記：
DynamoDBテーブルも自動で削除されないため、下記より手動で削除
https://ap-northeast-1.console.aws.amazon.com/dynamodb/home?region=ap-northeast-1#tables

# 手順（見直し前）

<details><summary> クリックで展開</summary><div>

### AWS IAMの作成

1.「AWS IAMの作成」章（書籍内60%位置付近）を参考に、アプリがDynamoDBにアクセスするためのAWS IAMを作成。
2.「zappa用のAWS IAMの作成」章（書籍内65%位置付近）を参考に、ZappaがAWSにコードをデプロイするためのAWS IAMを作成。

### MAC上のターミナルでDockerコンテナの作成

3.Python3.6の公式イメージを利用してコンテナを作成、ログイン

```shell
$ docker run -it --name pyserverless python:3.6 /bin/bash
```

### Dockerコンテナ上のbashでコード作成、デプロイ

4.Pipenvのインストール。Zappaを利用するのに必要 

```shell
$ pip install pipenv
```

5.サンプルコードをダウンロード 

```shell
$ git clone https://github.com/chaingng/serverless_python_tutorial.git
```

6.applicationフォルダに移動 

```shell
$ cd serverless_python_tutorial/application
```

7.Python3仮想環境の初期化 

```shell
$ pipenv --three
```

8.Pipenvシェル有効化 

```shell
$ pipenv shell
```

9.変数の指定

```shell
$ SERVERLESS_USER=[本番環境でのユーザーログインパスワード(任意の文字列)]
$ SERVERLESS_SECRET_KEY=[本番環境でのsecret(任意の文字列)]
$ SERVERLESS_AWS_ACCESS_KEY_ID=[項番1で作成したIAMアクセスキーID]
$ SERVERLESS_AWS_SECRET_KEY=[項番1で作成したIAMシークレットアクセスキー]
```

10.Pipfileに記載のパッケージとAWS CLIをインストール 

```shell
$ pipenv install
$ pipenv install awscli
```

11.bashrcの設定

```shell
$ cat << EOF >> ~/.bashrc
export SERVERLESS_BLOG_CONFIG=production
export SERVERLESS_USER=${SERVERLESS_USER}
export SERVERLESS_SECRET_KEY=${SERVERLESS_SECRET_KEY}
export SERVERLESS_AWS_ACCESS_KEY_ID=${SERVERLESS_AWS_ACCESS_KEY_ID}
export SERVERLESS_AWS_SECRET_KEY=${SERVERLESS_AWS_SECRET_KEY}
EOF
```

12.bashrc読み込み

```shell
$ . ~/.bashrc
```

13.AWS CLIプロファイルを作成

```
$ aws configure --profile serverless-blog
```

上記コマンドを実行すると対話式で入力を求められるので以下のように入力。

```
AWS Access Key ID [None]: [項番2で作成したIAMアクセスキーID]  #を入力
AWS Secret Access Key [None]: [項番2で作成したIAMシークレットアクセスキー] #を入力
Default region name [None]: ap-northeast-1 #を入力
Default output format [None]: #Enter押下
```

14.Zappa設定ファイルを編集

2019/6/8追記：
S3バケット名の重複エラー回避のため、`s3_bucket`の値がランダム値となるようにした。

```shell
$ cat << EOF > zappa_settings.json
{
    "dev": {
        "app_function": "server.app",
        "aws_region": "ap-northeast-1",
        "profile_name": "serverless-blog",
        "project_name": "application",
        "runtime": "python3.6",
        "s3_bucket": "serverless-blog-bucket-$RANDOM"
        "environment_variables": {
            "SERVERLESS_BLOG_CONFIG":"production",
            "SERVERLESS_USER_PW":"${SERVERLESS_USER}",
            "SERVERLESS_SECRET_KEY":"${SERVERLESS_SECRET_KEY}",
            "SERVERLESS_AWS_ACCESS_KEY_ID":"${SERVERLESS_AWS_ACCESS_KEY_ID}",
            "SERVERLESS_AWS_SECRERT_KEY":"${SERVERLESS_AWS_SECRET_KEY}"
        }
    }
}
EOF
```

15.Docker上のコードをAWSへデプロイ

```shell
$ zappa deploy
```

</div></details>

以上