AWS Chaliceの開発環境をdockerで構築し、超高速でサーバーレスアプリケーションをデプロイしてみた

# AWS Chaliceの開発環境をdockerで構築し、超高速でサーバーレスアプリケーションをデプロイしてみた

ChaliceもLambdaも初めてですが、
初めてのサーバーレスアプリケーションに興奮したので書きます

ソースコード [naokit-dev/python3_chalice_on_docker](https://github.com/naokit-dev/python3_chalice_on_docker)


## Chalice (チャリス?)

AWSが提供するPythonフレームワーク
Lambdaを使ったサーバーレスアプリケーションを簡単にデプロイできる
[Documentation — AWS Chalice](https://aws.github.io/chalice/index.html)

## 環境

- macOS Catalina
- VS Code
- Docker Desktop

```
docker --version
Docker version 19.03.13, build 4484c46d9d
docker-compose --version
docker-compose version 1.27.4, build 40524192
```
その他、**AWSのアクセスキーが必要になります**

## 準備運動

Docker Hubで使用するイメージを確認します
[python - Docker Hub](https://hub.docker.com/_/python)

AWS ChaliceはLambdaでサポートされているすべてのpythonが使用できるが3系が推奨とのこと

> AWS Chalice supports all versions of python supported by AWS Lambda, which includes python2.7, python3.6, python3.7, python3.8. We recommend you use a version of Python 3.
> [Quickstart — AWS Chalice](https://aws.github.io/chalice/quickstart.html)

ここでは、`3.8-alpine`を使用してみます

VS Codeで新規ワークスペースを作成
"python3_chalice_on_docker"としました

(次の手順は必要ないのですが、pythonが動く最小構成として試してみました)

Docker HubのイメージをPullしてコンテナを起動します

- -it 標準入力にアタッチ
- --rm コンテナ終了時にコンテナを削除
- -v <host_path>:<container_path> host_pathをボリュームとしてマウント

```sh
docker run -it --rm -v $PWD:/python python:3.8-alpine /bin/sh
```

(`-v .:/python`のように相対パスでマウントしようとするとエラーとなるが、環境変数`$PWD`が使えるようで`-v $PWD:/python`なら問題ない | [Volume相対パス指定でもdocker runがしたい！ - Qiita](https://qiita.com/KentoDodo/items/24117025924d64998110))

```
# python --version
Python 3.8.6
```
## Dockerfileを作成

先程作成したワークスペースでの作業になります

`Dockerfile`を作成
`pip install chalice`でchaliceをインストールします

```sh
touch Dockerfile
```

```sh
FROM python:3.8-alpine

WORKDIR /app

RUN pip install chalice

CMD [ "/bin/sh"]
```

つぎに`docker-compose.yml`を作成
ポートマッピング、ボリューム作成のほか、`.env`に記述した環境変数をコンテナ内で扱えるようにしています

```sh
touch docker-compose.yml
```

```yml
version: "3.8"
services:
  app:
    build: .
    ports:
      - "80:8000"
    volumes:
      - .:/app
    command: chalice local --host=0.0.0.0 --port=8000
    tty: true
    stdin_open: true
    working_dir: "${APP_PATH}"
    environment:
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
```

`.env`を作成
ここに環境変数を定義します
`APP_NAME`はいまはブランクのまま
ほかも今はそのままで構いませんが、AWSにデプロイするために必要なcredentialsを記述することになります

```sh
touch .env
```

```
APP_NAME=
APP_PATH=/app/${APP_NAME}
AWS_ACCESS_KEY_ID=[YOUR_ACCESS_KEY_ID]
AWS_SECRET_ACCESS_KEY=[YOUR_SECRET_ACCESS_KEY]
AWS_DEFAULT_REGION=ap-northeast-1
```

端末にAWSのcredentialsが保存されている場合
以下で確認できます

```
cat ~/.aws/credentials
```

## chalice projectを作成

`chalice new-project <project_name>`で新規プロジェクトを作成します

```sh
docker-compose run app chalice new-project test_chalice
```

以下のような構成になります

```txt
.
├── .env
├── Dockerfile
├── docker-compose.yml
└── test_chalice
    ├── .chalice
    │   └── config.json
    ├── .gitignore
    ├── app.py
    └── requirements.txt
```

## 環境変数を定義

`.env`を編集します
APP_NAMEに先程のプロジェクト名を、AWS_ACCESS_KEY_IDおよびAWS_SECRET_ACCESS_KEYもここに記述します
Regionは`ap-northeast-1`に設定してありますが適宜変更してください

```txt
APP_NAME=test_chalice
APP_PATH=/app/${APP_NAME}
AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxx
AWS_DEFAULT_REGION=ap-northeast-1
```

## ローカルサーバーをたてる

ローカルサーバーを起動

```sh
docker-compose up
```

docker-compose.ymlで`command: chalice local --host=0.0.0.0 --port=8000`としてコマンドを上書きしてあるので、`docker-compose up`時に`chalice local`が実行されます

`ports:      - "80:8000"`でホスト側のport 80をコンテナ内のport 8000にマッピングしてあるので、ホストから`localhost`にアクセスすると、chaliceのlocal serverにポートフォワーディングされます

```sh
curl localhost
{"hello":"world"}%
```
"hello world"が返ってきました

`test_chalice/app.py`をみてみます
以下のコメントアウトされている部分を、コメントアウト解除します

```
# @app.route('/hello/{name}')
# def hello_name(name):
#    # '/hello/james' -> {"hello": "james"}
#    return {'hello': name}
```

`/hello/chalice`にアクセスしてみると

```
curl localhost/hello/chalice
{"hello":"chalice"}%
```
"hello chalice"が返ってきました
RESTfulな挙動が確認できます


ローカルサーバーを停止

```
docker-compose down
```

## デプロイしてみる

`chalice deploy`でAWS Lambda関数としてデプロイされます

```sh
docker-compose run app chalice deploy

Creating deployment package.
Creating IAM role: test_chalice-dev
Creating lambda function: test_chalice-dev
Creating Rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:test_chalice-dev
  - Rest API URL: https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/
```
Rest API URLにアクセスしてみます

```
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/
{"hello":"world"}%

curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/hello/lambda
{"hello":"lambda"}%
```

chaliceがコードを解析し、
必要なIAM roleを付与してLambda関数としてデプロイしてくれるそうです

次は少し実用的なアプリに挑戦してみたいと思います

## Ref.
[Documentation — AWS Chalice](https://aws.github.io/chalice/index.html)