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

【Docker × Flask】FlaskAPIをGunicornのカスタムアプリケーションで起動する

作成日:2024月06月18日
更新日:2024年06月23日

dockerコンテナを使ってFlaskのアプリケーションをGunicornのカスタムアプリケーションとして
起動する方法をまとめる。

GunicornでFlaskのWEBアプリケーションを動かす場合下記の

  • Gunicornにアプリケーションインスタンスを直接渡す方法
  • Gunicornのカスタムアプリケーションとして起動する方法

二つの方法がある

二つの起動方法の違い

簡単に二つの起動方法の違いをまとめる

Gunicornにアプリケーションインスタンスを直接渡す方法

  • アプリケーションインスタンス(FlaskやDjango等)をGunicornに渡すだけなので簡単
  • アプリケーションの起動プロセスにカスタムロジックを追加するのは難しい

Gunicornのカスタムアプリケーションとして起動する方法

  • アプリケーションの起動プロセスにカスタムロジックを追加することが容易。
  • Gunicornにアプリケーションインスタンスを直接渡す方法に比べると実装が少し難しい。

なので、作るアプリケーションによって使い分ける必要がある

シンプルな「Gunicornにアプリケーションインスタンスを直接渡す方法」については
下記記事で紹介している

今回はより細かな設定ができる「Gunicornのカスタムアプリケーションとして起動する方法」を
試してみる

開発環境

  • Windows11
  • Docker version 26.1.1(Docker for Windows)
  • Flask 3.0.2
  • gunicorn 21.2.0

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

構成

プロジェクト構成は下記のようになる

プロジェクト構成
.
|-- Dockerfile
|-- app
| |-- __init__.py
| |-- __main__.py
| `-- app.py
|-- config
| `-- cfg.ini
|-- docker-compose.yml
`-- vscode_ex_install.sh

コンテナの設定

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

Dockerfile

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

docker-compose.yml

docker-compose.yml
version: "3"
services:
sample-api:
container_name: "flask_gunicorn"
build:
context: .
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
# バインドマウント
- .:/workspace
tty: true
  • dockerfileで作ったimageを元にコンテナを作る

requirements.txt

requirements.txt
Flask==3.0.2
gunicorn==21.2.0

上記を設定した上でプロジェクト直下で「docker compose up -d」を
実行すればコンテナが作成できる

コンテナ作成
$ docker compose up -d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
242a4af01ee2 flask-gunicorn-sample-api "python3" 42 seconds ago Up 38 seconds 0.0.0.0:5000->5000/tcp flask_gunicorn

カスタムアプリケーションの実装

flaskアプリをgunicornで起動するためのコンテナができたので
flaskアプリをgunicornのカスタムアプリケーションとして実装する

config/cfg.ini

cfg.iniファイルにgunicornの設定を書く

cfg.ini
[gunicorn]
bind = 0.0.0.0:5000
workers = 1
loglevel = info
; errorlog = /var/log/error.log
errorlog = -
accesslog = /var/log/access.log
  • コンテナで起動するため「0.0.0.0:5000」で起動する
  • errorlogは一旦は標準出力に出したいので-にしている

app/__init__.py

__init__.pyは空ファイルで問題ない

app/__main__.py

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

appパッケージのエントリーポイントとするため、ファイル名は「__main__.py」
にしておく。 別名にしたい場合は起動時にモジュールまで指定する必要がある
※詳しくは後述する

__main__.py
from configparser import ConfigParser
from gunicorn.app.base import BaseApplication
from app.app import flaskapp
class AppConfig:
@staticmethod
def load_config(path):
# 設定ファイルからGunicornの設定取得
config = ConfigParser()
config.read(path)
options = dict(config.items('gunicorn'))
return options
class CustumApplication(BaseApplication):
def __init__(self,app,options=None):
self.options = options or {}
self.application = app
super().__init__()
# Gunicornの設定をロードする
def load_config(self):
for key, value in self.options.items():
self.cfg.set(key.lower(), value)
# Gunicornがサーブするアプリケーションインスタンスをロードする
def load(self):
return self.application
if __name__ == '__main__':
# 設定ファイル読み込み
options = AppConfig.load_config('./config/cfg.ini')
# gunicornでアプリケーション起動
CustumApplication(flaskapp, options).run()

アプリケーションをgunicornのカスタムアプリケーションとする場合は下記は必須で
行う必要がある

  • BaseApplicationを継承する
  • load_configをオーバーライド
  • loadをオーバーライド

BaseApplicationを継承する

BaseApplicationはgunicornにおけるアプリケーションのベースクラスであるため
そのメソッドをオーバーライドすることでカスタムアプリケーションを作ることができる

load_configをオーバーライド

load_configはgunicornサーバーの設定を行うためのもの。
ここでConfigParserでcfg.iniファイルから読み込んだ設定情報を
セットする

roadをオーバーライド

Gunicornがサーブするアプリケーションインスタンスをロードする

app/app.py

FlaskのREST APIを作る
今回は動作確認に使う程度なのでシンプルなものを実装する

app.py
from flask import Flask
# flaskインスタンス作成
flaskapp = Flask(__name__)
# ディクショナリ
users = [
{"user_id": "1", "name": "tujimura", "age": 11},
{"user_id": "2", "name": "mori", "age": 20},
{"user_id": "3", "name": "shimada", "age": 50},
{"user_id": "4", "name": "kyogoku", "age": 70}]
@flaskapp.route('/', methods=['GET'])
def get_users():
# GETリクエストを処理
return users

起動する

コンテナに入って実装したgunicornのカスタムアプリケーションを起動する
起動は下記のコマンドで行う

起動
root@242a4af01ee2:/workspace# python -m app
[2024-06-12 07:16:05 +0000] [23654] [INFO] Starting gunicorn 21.2.0
[2024-06-12 07:16:05 +0000] [23654] [INFO] Listening at: http://0.0.0.0:5000 (23654)
[2024-06-12 07:16:05 +0000] [23654] [INFO] Using worker: sync
[2024-06-12 07:16:05 +0000] [23704] [INFO] Booting worker with pid: 23704

app配下に「__main__.py」があるため、コマンドではappパッケージを指定している。
エントリーポイントするファイル名が「__main__.py」出ない場合はそのモジュール名まで
指定する必要がある。

「python -m パッケージ」とした場合、pythonは指定したパッケージ内で「__main__.py」を
探し、存在すればそのスクリプトを実行する

「Gunicornにアプリケーションインスタンスを直接渡す方法」とは違い、アプリケーション経由で
Gunicornを起動するイメージ。

デバッグ方法

VScodeでデバッグする方法は下記のlaunch.jsonを作成する

launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Module",
"type": "debugpy",
"request": "launch",
"module": "app",
"console": "integratedTerminal",
"args": [],
"justMyCode": false,
"cwd": "${workspaceFolder}"
}
]
}

通常の起動とデバッグ起動で同じport番号5000を使うのでデバッグする時、または通常起動する時は
もう一方が停止してから行うようにする

まとめ

GunicornでFlaskのWEBアプリケーションをカスタムアプリケーションとして
起動する手順をまとめてみた。

個人的には特に複雑なことをしないようなら「Gunicornにアプリケーションインスタンスを直接渡す方法」で
作ったほうが簡単だし、わかりやすいと感じた。

参考

新着記事

タグ別一覧
top