ATP|搭建Docker + Flask + VUE + MySQL框架

45 阅读4分钟

假设我们的项目根目录是:my-flask-web

此文章我们搭起一个最基础的以python为核心的web框架,涉及到falsk蓝图设计、docker部署文件、mysql配置等,代码如何上传远程仓库我们这里不做赘述。下期我们将把项目在服务器跑起来。最后项目源码在文末,欢迎点赞&关注&讨论。

此项目在ubuntu服务器使用docker跑起来——OK

README.md文件(项目目录结构)

my-flask-web/
├── app/ # 后端应用
│ ├── __init__.py # 应用工厂
│ ├── models/ # 数据模型
│ │ ├── __init__.py
│ │ └── user.py
│ └── routes/ # 路由蓝图
│ ├── __init__.py
│ ├── main.py # 主路由
│ └── api.py # API 接口
├── client/ # 前端应用(Vue 3)
│ ├── src/
│ │ ├── main.js # 入口文件
│ │ ├── App.vue # 根组件
│ │ ├── router/ # 路由配置
│ │ └── views/ # 页面组件
│ ├── index.html
│ ├── vite.config.js
│ └── package.json
├── config.py # 配置文件
├── run.py # 启动文件
├── requirements.txt # Python 依赖
├── Dockerfile # Docker 镜像构建
├── docker-compose.yml # Docker 编排
├── .env.example # 环境变量示例
├── .gitignore
└── README.md

一、创建flask必备文件

1.1 程序入口文件:./run.py

from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

1.2 Flask 应用工厂:./app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config

db = SQLAlchemy()


def create_app(config_name='default'):
    """应用工厂模式"""
    app = Flask(__name__)
    app.config.from_object(config[config_name])

    # 初始化扩展
    db.init_app(app)

    # 注册蓝图
    from app.routes.main import main_bp
    from app.routes.api import api_bp

    app.register_blueprint(main_bp)
    app.register_blueprint(api_bp, url_prefix='/api')

    # 创建数据库表
    with app.app_context():
        db.create_all()

    return app

1.3 Flask配置文件:./config.py

import os
from dotenv import load_dotenv

load_dotenv()


class Config:

    """基础配置"""

    SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key')

    # MySQL 数据库配置
    MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')
    MYSQL_PORT = os.environ.get('MYSQL_PORT', 3306)
    MYSQL_USER = os.environ.get('MYSQL_USER', 'root')
    MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', 'your_password_data')
    MYSQL_DATABASE = os.environ.get('MYSQL_DATABASE', 'flask_app')
    
    SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}"
    SQLALCHEMY_TRACK_MODIFICATIONS = False


class DevelopmentConfig(Config):
    """开发环境配置"""
    DEBUG = True


class ProductionConfig(Config):
    """生产环境配置"""
    DEBUG = False


class TestingConfig(Config):
    """测试环境配置"""
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'


config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'testing': TestingConfig,
    'default': DevelopmentConfig
}

1.4 用户模型./app/models/user.py

from app import db
from datetime import datetime


class User(db.Model):
    """用户模型"""
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'created_at': self.created_at.isoformat() if self.created_at else None
        }

    def __repr__(self):
        return f'<User {self.username}>'

1.5 模型聚合文件:./app/models/__init__.py

from app.models.user import User

__all__ = ['User']

1.6 主路由蓝图:./app/routes/main.py

from flask import Blueprint, jsonify

main_bp = Blueprint('main', __name__)


@main_bp.route('/')
def index():
    """首页"""
    return jsonify({
        'message': '欢迎使用 Flask 应用',
        'status': 'success'
    })


@main_bp.route('/health')
def health():
    """健康检查端点"""
    return jsonify({
        'status': 'healthy'
    })

1.7 user 蓝图:./app/routes/api.py

from flask import Blueprint, jsonify, request
from app import db
from app.models import User

api_bp = Blueprint('api', __name__)


@api_bp.route('/users', methods=['GET'])
def get_users():
    """获取所有用户"""
    users = User.query.all()
    return jsonify({
        'users': [user.to_dict() for user in users],
        'count': len(users)
    })


@api_bp.route('/users', methods=['POST'])
def create_user():
    """创建新用户"""
    data = request.get_json()
    if not data or not data.get('username') or not data.get('email'):
    return jsonify({'error': '用户名和邮箱是必填项'}), 400
        user = User(
        username=data['username'],
        email=data['email']
    )

    db.session.add(user)
    db.session.commit()
    return jsonify({
        'message': '用户创建成功',
        'user': user.to_dict()
    }), 201


@api_bp.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    """获取指定用户"""
    user = User.query.get_or_404(user_id)
    return jsonify({'user': user.to_dict()})

1.8 蓝图聚合文件:./app/routes/__init__.py

from app.routes.main import main_bp
from app.routes.api import api_bp

__all__ = ['main_bp', 'api_bp']

1.9 包管理文件:·./requirements.txt

Flask==3.0.0
Flask-SQLAlchemy==3.1.1
PyMySQL==1.1.0
cryptography==41.0.7
python-dotenv==1.0.0
gunicorn==21.2.0
flask-cors==4.0.0

二、创建docker必要文件

我们项目使用flask+mysql+vue多个容器,使用docker-compose.yml文件进行编排各容器的关系

2.1 编排多个容器文件:./docker-compose.yml

networks:
    vplatform_net:
        driver: bridge

services:
    mysql-db:
        image: mysql:8.0
        container_name: mysql-db
        restart: always
        networks:
            - vplatform_net
        environment:
            # 自动读取你服务器本地 .env 里的密码
            MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
        # 数据持久化
        volumes:
            - /opt/vplatform/mysql_data:/var/lib/mysql
        ports:
            - "3306:3306"
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
            interval: 5s # 每 5 秒检查一次
            timeout: 5s # 超时时间 5 秒
            retries: 5 # 重试 5 次(总共给 MySQL 留出约 25 秒的启动时间)
            start_period: 10s # 容器启动后前 10 秒的失败不计入重试次数

    flask-app:
        build: .
        container_name: flask-app
        networks:
            - vplatform_net
        ports:
            - "22048:22048"
        environment:
            - MYSQL_HOST=mysql-db
            - MYSQL_PORT=3306
            - MYSQL_USER=root
            - MYSQL_PASSWORD=${MYSQL_PASSWORD}
            - MYSQL_DATABASE=design
            - SECRET_KEY=your_production_secret_key
        depends_on:
            mysql-db:
                condition: service_healthy # 严格依赖 mysql-db 的健康检查结果
        # 利用 Python 原生无依赖 socket 探测 22048 端口,确保 Flask 彻底启动
        healthcheck:
            test: ["CMD", "python3", "-c", "import socket; s = socket.socket(); s.connect(('127.0.0.1', 22048))"]
            interval: 5s
            timeout: 3s
            retries: 3
            start_period: 5s

    nginx:
        build: ./client
        container_name: nginx-frontend
        restart: always
        networks:
            - vplatform_net
        ports:
            - "808:80"
        depends_on:
            flask-app:
                condition: service_healthy # 严格依赖 flask-app 的健康检查结果

2.2 Docker 镜像构建文件:./Dockerfile

用来构建 Docker 镜像的配置文件。它定义了如何把你的应用打包成一个可移植的容器。

FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 22048

# Run the application
CMD ["gunicorn", "--bind", "0.0.0.0:22048", "run:app"]

2.3 docker过滤文件:./.dockerignore

作用是在构建 docker 镜像时排除不需要的文件,避免把垃圾文件打包进镜像。

__pycache__/
*.py[cod]
*$py.class
venv/
env/
.venv/
.env
.git/
.gitignore
.idea/
.vscode/
*.log
.DS_Store
*.md

2.4 环境变量模板文件:./.env.example

# 数据库配置
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=你的密码
MYSQL_DATABASE=flask_app

# Flask 配置
FLASK_APP=run.py
FLASK_ENV=development
SECRET_KEY=你的密钥

先在本地启动一下试试

$: ./venv/bin/python run.py
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:22048
 * Running on http://192.168.1.9:22048
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 601-756-088

项目源码地址恭喜看完,点个赞吧~