当サイトは、アフィリエイト広告を利用しています

【Docker × Flask】コンテナのFlaskAPIをGunicornで起動する方法

作成日:2024月02月23日
更新日:2024年03月22日

Dockerコンテナを使ってPythonのFlaskを使った開発ができる環境を
作成し、その中でFlaskの超簡単APIを作って外部サーバーであるGunicornで動作させて
動きを確認する

この記事を読めばflaskのプログラムを作って、Gunicorn上で
動かすまでの流れは理解できると思う。

flaskを使ったREST APIの実装については下記記事で紹介してます

プロジェクトの永続化について

コンテナで動作させるflaskプロジェクトの永続化方法について
永続化についてはバインドマウントを使用する

プロジェクトが大きくなってきた場合などは、バインドマウントではなく
名前付きボリュームをつかったほうがいいかもだが
とりあえず動きを確認するだけなので、バインドマウントで作成する。

Dockerのボリューム関係については下記記事でまとめているので
気になる方はご参照ください

またFlaskには開発用に内部サーバーがついているが
今回は外部サーバーであるGunicornを使って動かすようにする。

なぜ外部サーバーであるGunicornを使うのか?

flaskには簡易的な内部サーバーが付属しているため
gunicornなしでも動かすことができる。

開発段階では特に問題はないが、逆に開発段階から
gunicornを使うことで下記のようなメリットがある

パフォーマンスの向上

Gunicornは複数のワーカーを使用してリクエストを並行して処理することができる。
そのためFlaskの内部サーバーよりも高いパフォーマンスを出せる

ぶっちゃけ早い。

安定性の向上

Gunicornは本番環境での使用に耐えうる設計がされており
長時間の稼働においても安定している

柔軟な設定

Gunicornは多くの設定オプションがあり、アプリケーションのニーズに
合わせて細かく調整することが可能。

正直、簡単なAPIを作って動きを確認したいだけだが、
実際にサーバーにデプロイするとなると、内部サーバーではなく
外部サーバー(gunicorn等)を使う必要があるので
早い内から触っておこうという考え。

開発方法

開発はVScodeの拡張機能である「Remote Development」を
使ってVScodeからコンテナにアタッチして行う。

Remote Developmentを使ってコンテナにアタッチして
開発する方法については下記記事参照

コンテナはDockerComposeコマンドで作成して
作成済みのコンテナにVScodeからアタッチする方法を使う。

VScodeで拡張機能のRemote Developmentに含まれるDevContainersを
使ってコンテナ作成からVScodeでやる方法でも初めてもいいと思う。
※個人的にコンテナ作成はDockerComposeコマンドでやりたい派です。

環境

上記のような条件で開発をしていくので環境条件は下記のようになる

  • Windows10
  • Docker version 24.0.6(Docker for Windows)
  • VScode
  • Remote Development(VScodeの拡張機能)
  • Flask 3.0.2
  • gunicorn 21.2.0

Docker for Windowsのインストール方法については
下記記事で紹介しています

構成

全体的な構成は下記のようになる

プロジェクト構成
.
|-- Dockerfile
|-- app
| |-- api.py
| `-- wsgi.py
|-- docker-compose.yml
|-- gunicorn_config.py
`-- requirements.txt

Flaskアプリ動作コンテナの設定

コンテナをdocker-composeを使って構築するための
設定を各ファイルに書いていく。

Dockerfile

Dockerfile
FROM python:3.10
# workspaceディレクトリ作成、移動
WORKDIR /workspace
# プロジェクトディレクトリにコピー
COPY requirements.txt /workspace
# 必要モジュールのインストール
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
  • pythonのイメージを使用する
  • requirements.txtを使って必要なライブラリ等をインストールする

requirements.txt

requirements.txt
Flask==3.0.2
gunicorn==21.2.0

必要なライブラリをインストールする
今回はFlaskとgunicornだけとなる

docker-compose.yml

docker-compose.yml
version: "3"
services:
flaskapi:
container_name: "flask-api"
build:
context: .
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
# バインドマウント
- .:/workspace
# サーバー(gunicorn)実行
command: gunicorn wsgi:flask_api --config gunicorn_config.py
# command: gunicorn --reload -w 1 --bind 0.0.0.0:5000 --chdir /workspace/app wsgi:flask_api
tty: true
  • docker composeでコンテナ作成するための設定をかく
  • コンテナはDockerfileをbuiildして作成
  • 永続化はバインドマウントでする
  • サーバー起動はgunicorn_config.pyを読み込んで行う。

※コメントアウトしているコマンドについては後述する

api.py

api.py
from flask import Flask
# flaskアプリケーションインスタンス作成
flask_api = Flask(__name__)
@flask_api.route('/')
def hello():
return "Hello from Flask!!!"

アプリのエントリーポイントとなるファイル。

wsgi.py

wsgi.py
# api.pyのflaskインスタンスをimport
from api import flask_api
if __name__ == '__main__':
# gunicornサーバー起動
flask_api.run()

wsgi.pyは、WSGIサーバーとFlaskアプリケーションの接続を定義するファイルとして
役割を持たせるため、api.pyとは分けている。

wsgi.pyは本番環境でのデプロイメントにおいて、WSGI互換のサーバー(例えばGunicornやuWSGIなど)と
アプリケーションを接続するために使用される
※wsgi.pyはWSGIサーバーがアプリケーションオブジェクトを認識するためのエントリポイントとして機能し、
多くのサーバーとフレームワークがこのファイルをデフォルトで探しにくる

「flask_api」はapp.pyで作成したflaskアプリケーションインスタンス作成なので
名称は同じにしておく必要がある。
※というか同じもの。

「flask_api.run()」でgunicornサーバーを起動している。

gunicorn_config.py

gunicorn_config.py
# ワーカープロセスの数
workers = 1
# バインドするホストとポート
bind = '0.0.0.0:5000'
# リロードオプションを有効にする
reload = True
# ディレクトリの変更
chdir = '/workspace/app'

gunicornのコマンドライン引数をgunicorn_config.pyで
定義している。

引数の内容については上記ソースのコメントの通り

コマンドの「wsgi:flask_api」の部分に関しては GunicornがFlaskアプリケーションの場所を知るために必要な情報であり、
gunicorn_config.pyに記載することはできない。

また全部コマンド引数として書くことも可能でその場合は
コメントアウトしていたコマンドになる

コマンド
command: gunicorn --reload -w 1 --bind 0.0.0.0:5000 --chdir /workspace/app wsgi:flask_api

引数に全て書いた場合は「gunicorn_config.py」は使わないので不要となる。

設定が少なければ全部コマンドに書いてもいいかもしれない。

gunicornコマンドからアプリ起動までの流れ

gunicornコマンドからアプリ起動までについてちょっと詳しくまとめておく。

コマンドの解説

コマンド
command: gunicorn --reload -w 1 --bind 0.0.0.0:5000 --chdir /workspace/app wsgi:flask_api

のコマンドの重要なところはFlaskアプリケーションの場所を示してる
下記の部分になる、

コマンド
--chdir /workspace/app wsgi:flask_api

これは/workspace/app配下にあるwsgi.pyファイルのflask_api(flaskアプリケーションインスタンス)を
さしている。

つまりguniconrnでflaskアプリケーションインスタンスを
起動するという意味になっている。

そしてwsgi.pyでは

wsgi.py
# api.pyのflaskインスタンスをimport
from api import flask_api
if __name__ == '__main__':
# gunicornサーバー起動
flask_api.run()

importで呼ばれているわけではないので
if文の中に入り、flask_api.run()が実行される流れとなる。

初見は全然意味がわかりませんでした。。。

Flaskアプリ動作コンテナの作成

各種設定ファイルが完成したのでコンテナを作る

作成
$ docker compose up -d

コンテナ確認

確認
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a711645ba284 flask-simple-api-flaskapi "gunicorn wsgi:flask…" 4 seconds ago Up 2 seconds 0.0.0.0:5000->5000/tcp flask-api

問題なくできている。

Flaskアプリ動作コンテナの起動

docker-compose.ymlに起動コマンドを書いているので
コンテナを作成して時点でコンテナ内でgunicornが起動している

そのためホストのブラウザから「http://localhost:5000」にアクセスすると
下記のようにレスポンスが表示される。 2024-02-24-02-35-55

またはたホストのターミナル当で「curl http://localhost:5000」を
実行する

curl
$ curl http://localhost:5000
Hello from Flask!!!

とちゃんと帰ってくるのでサーバー起動できていることがわかる。

ホットリロードについて

gunicorn_config.pyで

gunicorn_config.py
# リロードオプションを有効にする
reload = True

としているのでホットリロードされるようになっている。
※コマンド引数の場合は「--reload」で指定している

サーバーの起動を自分でしたい場合

サーバーの起動を自分でしたい場合は
docoker-compose.ymlの下記の部分を消して
コンテナ作成する

docoker-compose.yml
version: "3"
services:
flaskapi:
container_name: "flask-api"
build:
context: .
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
# バインドマウント
- .:/workspace
# サーバー(gunicorn)実行
# command: gunicorn wsgi:flask_api --config gunicorn_config.py
# command: gunicorn --reload -w 1 --bind 0.0.0.0:5000 --chdir /workspace/app wsgi:flask_api
tty: true

そうすれば、コンテナ作成時に起動されない。

手動起動する場合

手動起動する場合はdocoker-compose.ymlでコメントアウトしている
コマンドをコンテナ内のターミナルで入力すれば起動できる。

gunicorn手動起動
root@08975fb0fe23:/workspace# gunicorn wsgi:flask_api --config gunicorn_config.py
[2024-02-23 17:44:02 +0000] [1230] [INFO] Starting gunicorn 21.2.0
[2024-02-23 17:44:02 +0000] [1230] [INFO] Listening at: http://0.0.0.0:5000 (1230)
[2024-02-23 17:44:02 +0000] [1230] [INFO] Using worker: sync
[2024-02-23 17:44:02 +0000] [1247] [INFO] Booting worker with pid: 1247

止めたい時は、「ctrl + c」で止める。

コンテナ起動と同時にgunicornを起動した場合、コンテナ内で停止されるには
killコマンドを使うしかないので、開発中などは手動起動にしておいたほうがいいかもしれない。
※「--reload」を設定している場合、killしてもすぐ新プロセスで起動するので
設定を変更する必要もある。。

サーバー起動をショートカット実行する

いちいちコマンドを打ち込むのが面倒な場合は
VScodeのタスクに登録しておけば、コマンドパレットからすぐ起動できる

2024-03-23-00-06-56

2024-03-23-00-09-32

2024-03-23-00-09-59

.vscode/task.jsonができるので下記のように書き換える

task.json
{
"version": "2.0.0",
"tasks": [
{
"label": "Run Gunicorn",
"type": "shell",
"command": "gunicorn",
"args": [
"wsgi:flask_api",
"--config",
"gunicorn_config.py"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

「F1」で「Run Gunicorn」を選ぶと起動する
2024-03-23-00-15-32

2024-03-23-00-16-43

まとめ

コンテナでflaskの超簡単なAPIを作って
Gunicornで動かすまでの流れをまとめてみた。

今後はもっと踏み込んでREST API等を作ってみる。
この記事で紹介してflaskapiのデバッグ方法については
下記記事で紹介しています

参考書籍

関連記事

新着記事

タグ別一覧
top