AWS FargateでFlaskを動かしてみる

この記事は[AWS Fargate Advent Calendar 2017](https://qiita.com/advent-calendar/2017/aws-fargate)の12/20分の記事です。

PythonのWebフレームワークであるFlask環境のFargateでの構築を、Dockerイメージ作成からやってみます。

数あるPythonのWebフレームワークの中でもFlaskはシンプルさと軽量がウリです。機械学習のデモアプリなどちょっとしたアプリを作るのに重宝しています。

# Dockerイメージの作成

以下を参考にFlask環境のDockerイメージを作ります。
http://containertutorials.com/docker-compose/flask-simple-app.html

flaskという名前のディレクトリを作って３つのファイルを置いていきます。
```$ mkdir flask```

```
flask/
　├ app.py
　├ requirements.txt
　└ Dockerfile
```

```python:app.py 
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Flask Dockerized'

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0')
```

```dockerfile:Dockerfile 
FROM ubuntu:latest
RUN apt-get update -y
RUN apt-get install -y python-pip python-dev build-essential
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["app.py"]
```

```requirements.txt 
Flask==0.10.1
```

Docker イメージを構築します。
```$ docker build -t flask-fargate:latest .```

作成してイメージがちゃんと動くかローカルで起動してみます。
```docker run -d -p 80:5000 flask-fargate```

http://サーバのIPアドレス:5000 にアクセスして「Flask Dockerized」と表示されれば正常に稼働しています。
なお、Flaskのデフォルトポートは5000です。EC2で検証する場合はTCPの5000番ポートのInboundを開放しておきましょう

# DockerイメージのECRへの登録
Fargateで動かすために、ECRにイメージを登録します。
Fargateは米国東部 (バージニア北部)リージョンでしか提供されていないので、AWSマネジメントコンソールでバージニア北部リージョンを選択します。
Amazon ECSの管理画面から[リポジトリ]→[リポジトリの作成]を選択します。

今回は「flask-fargate」という名前でリポジトリを作ります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/bcafafd4-e7e1-e811-52c0-c13ce9d3ab34.png)

次の画面で表示されるコマンドを実行します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/b795a26f-47b9-491c-da05-e894f581ea73.png)


1. aws ecr get-loginコマンドを実行 ```aws ecr get-login --no-include-email --region us-east-1```
2. aws ecr get-loginコマンドが返した文字列をコマンドとして実行 ```docker login で始まる長いコマンド```
3. イメージにタグ付け ```docker tag flask-fargate:latest xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/flask-fargate:latest```
4. AWSリポジトリにイメージをプッシュ ```docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/flask-fargate:latest```

これでECRへのイメージの登録は完了です。

# ECSクラスターの作成
Amazon ECSの管理画面から[クラスター]→[クラスターの作成]を選択します。
[Networking only]を選択して[次のステップ]へ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/3d443729-f4dd-9274-baa7-4795832fc900.png)

クラスター名に今回は「flask-fargate」を入力、[Create VPC]にチェックを入れます。以降はデフォルト値のままにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/6ccc750a-4382-7d04-50db-565fd83e6866.png)

作成を選択すると、クラスターと関連リソースのデプロイが始まるので、完了するのを待ちます。

# ECSタスク定義の作成

Amazon ECSの管理画面から[タスク定義]→[新しいタスク定義の作成]を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/20e91255-0ff4-7e14-8bf6-a661494880da.png)

Launch typeはもちろん「FARGATE」を選びます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/da33f054-8591-f739-b9a7-4b1d3d7a125c.png)

タスク定義名を入力します。今回は「flask」としました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/8afbc861-e2f3-4985-ea48-d9c94db2f8a9.png)

タスクサイズではメモリとCPUの量を指定します。今回は最小構成のメモリ0.5GB、VPU 0.25vCPUとしました。
他はデフォルト値にしています。
[コンテナの追加]を選択。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/7c04b670-b81a-562d-7db6-a24c2987ea0c.png)


コンテナ名を入力します。今回は「flask」としました。
イメージには先ほど作成したECR上のイメージのURLを入力します。ポートマッピングには5000番を指定します（Flaskのデフォルトポート）。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/bac7d192-ee07-d4b8-17f1-d45be9921b96.png)

コンテナが追加されたので、[作成]を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/c870a7e9-2f19-93de-4a20-c8ff629c4d92.png)

これでタスク定義の作成は完了です。

# サービスの作成

Amazon ECSの管理画面から[クラスター]→さっき作った flask-fargate クラスター を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/8f8d5899-a7ee-1bbe-2ad8-8b76b2302621.png)

[サービス]タブから[作成]を選択します。
サービスの設定画面でLaunch typeに「FARGATE」を選びます。タスク定義、クラスターは作成したものを選択します。
サービス名は今回は「flask_first」としました。タスク数は1としておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/7c73ecd0-2089-6b4f-1486-e76a9d46c36f.png)

クラスター作成時にセットで作成されたVPCを指定、ELBは今回はなしにしておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/22809b19-035e-3e04-0436-77d0f32ff0bb.png)

サービスの作成が完了すると、タスクの実行が開始されます。

# 接続確認

タスクの詳細からNetworkカテゴリのENI idをクリックすると、コンテナのパブリックIPアドレスが確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/c714a973-be15-6ced-f2b7-29cdab571db8.png)

http://サーバのIPアドレス:5000 にアクセスして、以下のように表示されればOKです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/69163/efb83bab-a83a-181d-7dcc-7e7beb619b61.png)


# まとめ

Dockerはこれまで少し触ったことはありましたが、Dockerホストを立てたり、ECSを使う場合もクラスタの管理が必要だったりと、最初の手間があってあまり使っていませんでした。Fargateならイメージを用意すれば、ホストやクラストの管理をあまり意識することなく、敷居が一気に下がった気がします。
社内の検証環境や開発環境にいろいろと使っていきたいと思います


# おまけ
Flaskを使った機械学習デモアプリの作り方です。ファイルアップロードや画像の前処理、Chainerモデル利用まで小規模なコーディングで実現できるのでおすすめです！

[ChainerとFlaskで作る機械学習デモアプリ 後編 Webアプリの構築 | ナレコムAI レシピ](https://recipe.narekomu-ai.com/2017/10/chainer_web_demo_2/)