エンジニア管理ツールでも作る③Flask・Gunicorn環境用意

# 前回
Next.jsの環境を作りました。

https://qiita.com/k-jimon/items/34becb7bd9aabdae6d10

# 今回の目標
DockerでFlask + Gunicorn環境を作る


# Dockerfileの用意
```dockerfile
# api/Dockerfile
FROM python:3-slim

WORKDIR /app

RUN pip install --upgrade pip

COPY requirements.txt ./
RUN pip install -r requirements.txt
```

現時点でpython:3-slimのバージョンは3.12.3でした。

pipはとりあえずupdrageしておきます。

`requirements.txt`には必要なパッケージ一覧を羅列する予定です。

`RUN pip install -r requirements.txt`を`Dockerfile`に書くかは好みの問題なのかもしれませんが、今回は書いています。
イメージがPythonパッケージをインストールした状態で作成されます。
じゃあ他にどういう方法があるんだというと、`docker-compose.yml`の`commands`のところに書く方法があります。

`Dockerfile`の方に書いておくと、`docker compose restart`などしたときにPythonパッケージはインストール済みなのですぐにリスタートされます。
そのかわり、`requirements.txt`を編集する度に`docker compose build`してやる必要があります。

`docker-compose.yml`の書いておくと、`requirements.txt`を編集する度に`docker compose build`する必要は無くなりますが、`docker compose restart`などしたときにPythonパッケージのインストールが挟まり、リスタートが少し遅れます。


### Dockerイメージのタグについて
Dockerfileに`FROM XXX`と書いた場合、基本的に[docker hub](https://hub.docker.com/)というところからイメージをpull(ダウンロード)してきます。

今回、`FROM python:3-slim`と指定しましたが、`python`の部分が基本となるイメージ名、`3-slim`の部分がタグというものになります。

[docker hubのpythonのページ](https://hub.docker.com/_/python)を確認すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537927/4e45c208-8ff1-16c8-1eb3-7b6aa0f46f1d.png)

`3-slim`は`3.12.3-slim`とかと同じところに書かれていますね。
pythonの公式は現時点でこのバージョンをオススメしているわけです。

なので、時間が経つと`3-slim`は移動して`3.13-slim`とかを指すことになるはずです。

> 現時点でpython:3-slimのバージョンは3.12.3でした。

ここで「現時点で」という言葉を使ったのはそのためです。


# docker-compose.ymlの用意
```yml
# docker-compose.yml
services:
  api:
    build: api
    image: sk-api
    volumes:
      - ./api:/app
    ports:
      - "8001:8000"
    command: 'gunicorn'
```

`gunicorn`一発で立ち上がるように設定を頑張ります。


# requirements.txtの用意
```yml
# api/requirements.txt
Flask
gunicorn
```
とりあえず今はこれだけあればOKです。


# flaskアプリ
```python
from flask import Flask

app = Flask(__name__)

@app.route('/api')
def hello():
    return {"hello": 200}
```

最小構成でやってみます。

# Gunicorn設定
## Gunicornとは
WSGI（Web Server Gateway Interface）サーバーというやつです。
「ウィズギー」と読みます。

Flaskだけでも動作自体はするんですけど、
Gunicornは複数のワーカープロセスを生成し、それぞれがリクエストを処理することで並行処理を実現します。
これにより、複数のクライアントからの同時リクエストに対応でき、高負荷時でも安定して動作します。

Flaskはリクエストを受け取って実際の処理をするもの。
Gunicornはリクエストの送受信を制御するもの。
と考えればいいと思います。

## 設定
```python
# api/gunicorn.conf.py
import os

wsgi_app = 'app:app'

reload = True
bind = '0.0.0.0:8000'

workers = os.cpu_count()
```

`gunicorn.conf.py`というファイルを作ると自動で読み込んでくれます。

`wsgi_app`にflaskで作ったアプリを設定します。
`app.py`の中の`app`モジュールがflaskアプリなので`'app:app'`と設定します。

`reload = True`とすることで、コードを変更したときに勝手にワーカーを再起動してくれます。

`bind = '0.0.0.0:8000'`でどのIPのどのポートで起動するかを設定します。

`workers`にはワーカーの数を設定します。デフォルトは1です。
公式からの推奨値は`(CPU * 2) +1`です。
私のPCのCPUは`3`で、とりあえずこれで十分なので`workers = os.cpu_count()`としてます。
画面を作っていく上で動きがもっさりしてきたら、ここの値を変更していこうと思います。

# ディレクトリ構成

```
api
├── Dockerfile
├── app.py
├── gunicorn.conf.py
└── requirements.txt
```

最終的にはこんな感じです。

# 起動
```terminal
docker compose up -d
```

`localhost:8001/api`にアクセスしてみましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537927/54707242-45e3-bd52-5eca-3e230c42a490.png)

ちゃんとjsonが返ってきてますね。

ね、簡単でしょう？


# 次回
Nginxの環境用意

https://qiita.com/k-jimon/items/6bf835c5fe538a462b9c