3ad430e3e3
支持两种部署模式,兼容新建 MySQL 和现有 MySQL: - Dockerfile:Python 3.12-slim 两阶段构建,非 root 运行 - docker-compose.yml:全栈模式(含 MySQL 8.0 + 可选 Nginx) - docker-compose.external-db.yml:接入现有 MySQL 模式 - docker/entrypoint.sh:自动等待 DB 就绪 → 初始化表 → 启动 Gunicorn - docker/nginx.conf:反向代理 + 静态文件直出 + 安全响应头 - .env.docker.example / .env.external-db.example:各模式配置示例 - .gitattributes:确保 entrypoint.sh 在 Windows 上保持 LF 换行 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
4.4 KiB
YAML
119 lines
4.4 KiB
YAML
# ═══════════════════════════════════════════════════════════════
|
|
# docker-compose.yml — 模式一:新建 MySQL(全栈部署)
|
|
#
|
|
# 用法:
|
|
# cp .env.docker.example .env.docker
|
|
# # 编辑 .env.docker 修改密码和 SECRET_KEY
|
|
# docker compose --env-file .env.docker up -d
|
|
#
|
|
# 包含服务:
|
|
# db — MySQL 8.0
|
|
# app — Flask + Gunicorn
|
|
# nginx — Nginx 反向代理(可选,使用 --profile nginx 启用)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
services:
|
|
|
|
# ── MySQL 数据库 ────────────────────────────────────────────
|
|
db:
|
|
image: mysql:8.0
|
|
container_name: resource_library_db
|
|
restart: unless-stopped
|
|
environment:
|
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
|
MYSQL_DATABASE: ${MYSQL_DATABASE:-resource_library}
|
|
MYSQL_USER: ${MYSQL_USER:-resource_library}
|
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
|
volumes:
|
|
- mysql_data:/var/lib/mysql
|
|
- ./docker/mysql-init:/docker-entrypoint-initdb.d:ro # 可放自定义初始化 SQL
|
|
command: >
|
|
--character-set-server=utf8mb4
|
|
--collation-server=utf8mb4_unicode_ci
|
|
--default-authentication-plugin=mysql_native_password
|
|
--innodb-buffer-pool-size=256M
|
|
ports:
|
|
- "${MYSQL_EXPOSE_PORT:-127.0.0.1:3306}:3306" # 默认仅本机可访问
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost",
|
|
"-u", "${MYSQL_USER:-resource_library}",
|
|
"-p${MYSQL_PASSWORD}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 30s
|
|
networks:
|
|
- backend
|
|
|
|
# ── Flask 应用 ──────────────────────────────────────────────
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: resource_library_app
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
FLASK_ENV: ${FLASK_ENV:-production}
|
|
SECRET_KEY: ${SECRET_KEY}
|
|
DATABASE_URL: mysql+pymysql://${MYSQL_USER:-resource_library}:${MYSQL_PASSWORD}@db:3306/${MYSQL_DATABASE:-resource_library}
|
|
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
|
|
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-Admin@123456}
|
|
ADMIN_EMAIL: ${ADMIN_EMAIL:-admin@example.com}
|
|
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-4}
|
|
GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-120}
|
|
MAX_UPLOAD_SIZE_MB: ${MAX_UPLOAD_SIZE_MB:-500}
|
|
LOG_LEVEL: ${LOG_LEVEL:-info}
|
|
volumes:
|
|
- uploads_data:/app/app/static/uploads
|
|
ports:
|
|
- "${APP_PORT:-5000}:5000" # 使用 Nginx 时可去掉此行
|
|
networks:
|
|
- backend
|
|
- frontend
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "20m"
|
|
max-file: "5"
|
|
|
|
# ── Nginx 反向代理(可选,加 --profile nginx 启用)──────────
|
|
nginx:
|
|
image: nginx:1.27-alpine
|
|
container_name: resource_library_nginx
|
|
restart: unless-stopped
|
|
profiles: ["nginx"]
|
|
depends_on:
|
|
- app
|
|
ports:
|
|
- "${NGINX_HTTP_PORT:-80}:80"
|
|
- "${NGINX_HTTPS_PORT:-443}:443"
|
|
volumes:
|
|
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
|
- uploads_data:/app/app/static/uploads:ro # 让 Nginx 直接服务静态文件
|
|
# - ./docker/ssl:/etc/nginx/ssl:ro # HTTPS 证书目录(取消注释后使用)
|
|
networks:
|
|
- frontend
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
# ── 持久化卷 ────────────────────────────────────────────────────
|
|
volumes:
|
|
mysql_data:
|
|
name: resource_library_mysql
|
|
uploads_data:
|
|
name: resource_library_uploads
|
|
|
|
# ── 网络 ────────────────────────────────────────────────────────
|
|
networks:
|
|
backend:
|
|
name: resource_library_backend
|
|
internal: true # db 不暴露给外部网络
|
|
frontend:
|
|
name: resource_library_frontend
|