【環境構築】【テンプレート】DockerでWebアプリケーション開発環境を構築してみた!!(Nginx+Python+Flask+uWSGI+MySQL)

python

目的

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

動作確認

「http://127.0.0.1:8000/」へアクセスして表示を確認する。

「http://127.0.0.1:3000/」へアクセスして表示を確認する。

タイトルとURLをコピーしました