タイトルのとおりですが、Flaskで作ったAPIサイトをuWSGI+Nginxの構成で、Docker上に構築してみました。
この構成であれば、かなり本番運用に近い構成なのではないかと思います。
作業用ディレクトリの作成
作業用ディレクトリとして、flask-uwsgiを作成します。
mkdir flask-uwsgi
cd flask-uwsgi
Flask
まず、FlaskでのAPIサイトですが、下記のような感じで適当に作りましょう。
Flask-CORSなんかも入れておくと良いですよね。
MySQLからデータを取得するようにしてあります。MySQLの接続情報は環境変数から取ることにしています。
from flask import Flask, Response, request, jsonify
from flask_cors import CORS
import mysql.connector
import os
app = Flask(__name__)
CORS(app)
@app.route('/api/v1/get_user/<int:id>', methods=['GET'])
def get_user(id):
conn = mysql.connector.connect(
host=os.environ['MYSQL_HOST'] or 'localhost',
port=os.environ['MYSQL_PORT'] or 3306,
user=os.environ['MYSQL_USER'],
password=os.environ['MYSQL_PASSWORD'],
database=os.environ['MYSQL_DATABASE']
)
cur = conn.cursor(dictionary=True)
cur.execute('SELECT * FROM users WHERE id=%s LIMIT 1', (id,))
user = cur.fetchone()
return jsonify({
'id': id,
'user_name': user['name']
})
app.ini
uWSGIで動かすために、app.iniを作成します。
[uwsgi]
module = app
callable = app
die-on-term = true
chdir = /app
processes = 1
master = false
vacuum = true
socket = /tmp/uwsgi.sock
chmod-socket = 666
requirements.txt
Flaskの動作に必要なパッケージをインストールするため、requirements.txtを作成します。
Flask==2.0.3
Flask-Cors==3.0.10
uWSGI==2.0.20
mysql-connector-python==8.0.28
Dockerfileの作成とDockerコンテナイメージの作成
ここまでのファイルを1つのディレクトリ(flask-uwsgi)内にひとまとめにして、同じフォルダにDockerfileを作ります。
ベースイメージとして、alpineという軽量Linux上で動作するPythonのイメージを使用します。
COPYでカレントディレクトリのファイルを、コンテナ上の/appディレクトリにコピーし、そこを作業ディレクトリとします。
パッケージのインストール時にビルドが必要なため、いくつかのalpineのパッケージをインストールしています。
FROM python:alpine
WORKDIR /app
COPY . /app
RUN apk --update-cache add \
gcc \
g++ \
build-base \
linux-headers \
python3-dev \
pcre-dev
RUN pip install -r requirements.txt
Dockerコンテナイメージの作成は下記のようにします。
docker image build -t flask-uwsgi .
ビルドが成功すれば、Dockerコンテナイメージは作成完了です。
Nginx
いま作ったDockerコンテナイメージはuWSGIのソケットを介してFlaskが動作するものであるため、NginxでHTTPリクエストを受け付けてuWSGIのソケットを呼び出すようにします。
flask-uwsgiと同じ階層に、webディレクトリを作成します。
cd ..
mkdir web
webディレクトリにnginx.confファイルを作成し、下記のようにします。
server {
listen 80;
server_name localhost;
location /api/ {
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
}
}
Nginx環境は公式のDockerコンテナイメージを試用するだけなので、特にDockerfileは作りません。
docker compose
最後に、flask-uwsgiやwebディレクトリと同じ階層に、docker-compose.yamlファイルを作成し、下記のようにします。
environmentで環境変数を指定することで、MySQLの接続情報を引き渡します。
また、/tmpディレクトリを共有してソケットでの通信を可能にします。
version: '3'
services:
app:
image: flask-uwsgi
environment:
- MYSQL_HOST=<MySQLホスト>
- MYSQL_PORT=3306
- MYSQL_USER=<MySQLユーザー名>
- MYSQL_PASSWORD=<MySQLパスワード>
- MYSQL_DATABASE=<データベース名>
volumes:
- socket:/tmp
command: uwsgi --ini /app/app.ini
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./web/nginx.conf:/etc/nginx/conf.d/default.conf
- socket:/tmp
volumes:
socket:
後は、起動するだけです。
docker compose up -d
ちゃんとデータベースを作っていれば、http://localhost/api/v1/get_user/1などとアクセスすると、ユーザーの名前が返ってくるはず。
終了する場合は、下記のとおり。
docker compose down
今回はFlaskのソースコードをイメージの中に組み込んでいるので、本番リリースなどにも対応できると思います。
CI/CDを構成する場合は、FlaskのソースコードをGitリポジトリにコミットしたら、自動的にDockerコンテナイメージができるという形が良いと思います。
逆に、開発環境として使用する場合は、PC上のカレントディレクトリが見える形にすることになるでしょう。