目的
Nginx+Python+Flask+uWSGI+MySQLの開発環境を構築する。
イメージ
環境
バージョン
- コンテナ
- Python : 3.11.4
- Flask : 2.3.2
- NGINX : 1.25.2
- uWSGI : 2.0.22
- MySQL : 8.1.0
ディレクトリ構成
test
├── app
│ ├── Dockerfile
│ └── src
│ ├── app.py
│ ├── config.py
│ ├── requirements.txt
│ ├── run.py
│ ├── templates
│ │ └── list.html
│ ├── users.py
│ └── uwsgi.ini
├── db
│ ├── init
│ │ └── createdatabase.sql
│ └── variables.env
├── docker-compose.yml
└── web
├── default.conf
└── nginx.conf
ソースコード
Docker
docker-compose.yml
version: '3'
services:
db:
image: mysql
container_name: db-server
hostname: db-server
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always
ports:
- "33306:3306"
expose:
- "3306"
volumes:
- ./db/init:/docker-entrypoint-initdb.d
env_file:
- ./db/variables.env
app:
image: python:3.11
build:
context: ./app
container_name: ap-server
hostname: ap-server
volumes:
- ./app/src:/var/www/html/
restart: always
tty: true
expose:
- "8001"
env_file:
- ./db/variables.env
command: uwsgi --ini /var/www/html/uwsgi.ini
depends_on:
- db
web:
image: nginx
container_name: web-server
hostname: web-server
ports:
- "8000:8000"
volumes:
- ./web/nginx.conf:/etc/nginx/nginx.conf
- ./web/default.conf:/etc/nginx/conf.d/default.conf
restart: always
depends_on:
- app
phpmyadmin:
image: phpmyadmin
container_name: phpmyadmin
depends_on:
- db
environment:
- PMA_ARBITRARY=1
- PMA_HOSTS=db
- PMA_USER=test
- PMA_PASSWORD=test
ports:
- "3000:80"
Webコンテナ:Nginxの設定
default.conf
# リバースプロキシ設定:バックエンドのサーバを指定
upstream backend1 {
ip_hash;
server ap-server:8001; # container_nameで指定
}
server {
listen 8000;
server_name web-server; # container_nameで指定
charset utf-8;
# "/"から始まるURIに{}内の設定を適用する
location / {
uwsgi_pass backend1;
# バックエンドのサーバに追加のヘッダ情報を引き渡す
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $hostname;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
include /etc/nginx/uwsgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
APコンテナ:Python+Flask+uWSGI
Dockerfile
FROM python:3.11
RUN mkdir -p /var/www/html/
WORKDIR /var/www/html/
COPY src .
RUN mkdir -p /var/log/uwsgi
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install -r requirements.txt
app.py
import config
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# Create Flask Application
application = Flask(__name__)
# Set Config Class
application.config.from_object('config.Config')
# Set DB
db = SQLAlchemy(application)
config.py
import os
class DbConfig:
SQLALCHEMY_ECHO = True
# DB URL : 環境変数で設定する
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{user}:{password}@{host}:{port}/{dbname}?charset=utf8'.format(**{
'user': os.getenv('MYSQL_USER', 'root'),
'password': os.getenv('MYSQL_PASSWORD', ''),
'host': os.getenv('MYSQL_HOST', 'localhost'),
'port': os.getenv('MYSQL_PORT', ''),
'dbname': os.getenv('MYSQL_DATABASE')
})
Config = DbConfig
run.py
from app import application
from users import Users
from flask import render_template
@application.route('/')
def index():
users = Users.query.order_by(Users.id).all()
return render_template('list.html', users=users)
if __name__ == '__main__':
application.run(host='0.0.0.0', port='8000',debug=True)
users.py
from app import db
class Users(db.Model):
'''
Users Table Model
'''
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255))
email = db.Column(db.String(255))
def __init__(self,name,email):
self.name = name
self.email = email
uwsgi.ini
[uwsgi]
# 実行するファイル
module = run
# アプリケーションオブジェクトの変数名
callable = application
# root権限で実行する
master = true
# 稼働させるワーカープロセス数
processes = 1
socket = :8001
# ソケットファイルの権限
chmod-socket = 666
#
vacuum = true
#
die-on-term = true
# wsgiで動作させるファイルのパス
wsgi-file = /run.py
# ロギング
logto = /var/log/uwsgi/%n.log
# オートリロード機能の間隔:1秒ごとにリクエストがあればリロードするという設定
py-autoreload = 1
requirements.txt
Flask
uwsgi
flask-sqlalchemy
PyMySQL
templates/list.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flask Sample</title>
</head>
<body>
<h1>Flask Sample</h1>
<table border="1" style="border-collapse: collapse">
<thead>
<tr>
<th >Id</th>
<th >Name</th>
<th >EMail</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.email}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
.env
HOME_PATH = './'
ROOT_PATH = '/var/www/html/'
DBコンテナ:MySQL
init/createdatabase.sql
USE app;
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
email VARCHAR(255)
);
INSERT INTO users(name,email) VALUES('sample','sample@sample.com');
INSERT INTO users(name,email) VALUES('test','test@test.com');
INSERT INTO users(name,email) VALUES('app','app@app.com');
GRANT ALL ON app.* TO test;
variables.env
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=test
MYSQL_PASSWORD=test
MYSQL_DATABASE=app
MYSQL_HOST=db-server
MYSQL_PORT=3306
実行(コンテナ起動)
以下コマンドを実行してコンテナを起動する。
$ docker-compose build
$ docker-compose up
$ docker ps