Skip to content

Docker 快速部署

本章节介绍如何使用 Docker 快速部署后端服务,无需手动安装 Python、MySQL、Redis 等环境。

温馨提示

Docker 部署适合快速体验和生产环境。本地开发建议使用 后端启动 章节的方式。

前置条件

确保已安装 Docker 和 Docker Compose:

bash
# 验证 Docker 安装
docker --version
# Docker version 24.0.x

# 验证 Docker Compose 安装
docker compose version
# Docker Compose version v2.x.x

快速启动

1. 准备环境变量

bash
# 复制环境变量模板
cp .env.example .env

# 编辑 .env,配置数据库密码、Redis 密码、JWT 密钥等

重要提示

Docker 部署时,.env 中的 DB_HOSTREDIS_HOST 应指向 Docker 网络中的服务名称(如 mysqlredis),而非 127.0.0.1

2. 使用 Docker Compose 启动

bash
# 构建并启动所有服务
docker compose up -d --build

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f app

3. 访问服务

后端 API: http://127.0.0.1:8041/api/v1/health

Dockerfile 说明

项目使用多阶段构建,减小镜像体积:

dockerfile
# ======================================================================
# Stage 1: 构建依赖
# 使用一个临时镜像来解析 Poetry 依赖,避免把 Poetry 本身
# 和构建缓存带入最终运行镜像,从而减小镜像体积。
# ======================================================================
FROM python:3.12-slim AS builder

# 设置构建阶段的工作目录
WORKDIR /build

# 只拷贝依赖描述文件(先拷这些可以利用 Docker 层缓存:
# 只要依赖没变,后续 poetry export 就不会重新执行)
COPY pyproject.toml poetry.lock* ./

# 安装 Poetry,并把 pyproject.toml / poetry.lock 中的依赖
# 导出为普通的 requirements.txt,方便运行阶段用 pip 安装。
# --without-hashes:不写入哈希校验,简化后续安装。
RUN pip install --no-cache-dir poetry \
    && poetry export -f requirements.txt -o requirements.txt --without-hashes


# ======================================================================
# Stage 2: 运行
# 基于干净的 python:3.12-slim 构建最终镜像,只保留运行所需内容。
# ======================================================================
FROM python:3.12-slim AS runtime

# 环境变量配置:
# PYTHONUNBUFFERED=1      → 不缓冲 stdout/stderr,日志实时输出
# PYTHONDONTWRITEBYTECODE=1 → 不生成 .pyc 文件,保持镜像干净
# TZ=Asia/Shanghai        → 设置容器时区为上海
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    TZ=Asia/Shanghai

# 设置应用运行的工作目录
WORKDIR /data/apps

# 从构建阶段拷贝导出的 requirements.txt
COPY --from=builder /build/requirements.txt ./

# 安装运行所需的 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt

# 拷贝应用代码和资源文件到镜像中
COPY src ./src                 # 源码目录
COPY app.py ./                 # 应用入口
COPY alembic ./alembic         # 数据库迁移脚本
COPY alembic.ini ./            # 数据库迁移配置
COPY .env.example ./.env       # 环境变量示例(默认作为 .env 使用)
COPY scripts ./scripts         # 辅助脚本
COPY templates ./templates     # 模板文件
COPY static ./static           # 静态资源

# 创建运行时需要的上传目录和日志目录
RUN mkdir -p uploads logs

# 声明容器对外暴露的端口
EXPOSE 8041

# 容器启动命令:运行 Tornado 应用入口
CMD ["python", "app.py"]

多阶段构建原理

┌─────────────────────────────────────────────────────────────┐
│ Stage 1: builder                                            │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ python:3.12-slim                                        │ │
│ │ + Poetry                                                │ │
│ │ + pyproject.toml / poetry.lock                          │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ → poetry export → requirements.txt                      │ │
│ └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼ 仅拷贝 requirements.txt           │
│ Stage 2: runtime                                             │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ python:3.12-slim                                        │ │
│ │ + pip install -r requirements.txt                       │ │
│ │ + 应用源码 + 配置 + 脚本                                 │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ → 最终镜像(不含 Poetry、不含构建缓存)                    │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

docker-compose.yml 说明

基础版(仅应用服务)

项目自带的 docker-compose.yml 仅包含应用服务,适用于数据库和 Redis 已有外部实例的场景:

yaml
# ======================================================================
# Docker Compose 编排文件(基础版)
# 仅包含应用服务,适用于数据库和 Redis 已有外部实例的场景
# 使用方式:docker compose up -d
# 依赖根目录下的 .env 提供环境变量
# ======================================================================

services:
  # ====================================================================
  # 应用服务:构建并运行本项目
  # ====================================================================
  tornado_antdvue:
    image: tornado_antdvue:latest          # 镜像名称
    container_name: tornado_antdvue        # 容器名称
    build:
      context: ./                         # 构建上下文为项目根目录
      dockerfile: Dockerfile              # 使用项目根目录的 Dockerfile
    restart: always                       # 总是自动重启(生产环境推荐)
    ports:
      - "8041:8041"                       # 宿主机端口:容器端口
    environment:
      - TORNADO_PORT=8041                 # 应用监听端口
      - TORNADO_ENV=production            # 运行环境设为生产模式
    env_file:
      - .env                              # 从 .env 文件加载数据库密码等环境变量
    volumes:
      - ./uploads:/data/apps/uploads      # 持久化上传文件到宿主机
      - ./logs:/data/apps/logs            # 持久化日志(与 Dockerfile WORKDIR 对应)
    command: python app.py                # 启动命令
    logging:
      driver: "json-file"                 # 日志驱动:JSON 文件
      options:
        max-size: "500m"                  # 单个日志文件最大 500MB
        max-file: "10"                    # 最多保留 10 个日志文件

完整版(应用 + MySQL + Redis)

快速体验或小型部署推荐使用包含 MySQL 和 Redis 的完整版:

yaml
# ======================================================================
# Docker Compose 编排文件(完整版)
# 包含三个服务:app(应用)、mysql(数据库)、redis(缓存)
# 使用方式:docker compose up -d
# 依赖根目录下的 .env 提供密码等环境变量
# ======================================================================

services:
  # ====================================================================
  # 应用服务:构建并运行本项目
  # ====================================================================
  app:
    build: .                                # 使用当前目录的 Dockerfile 构建镜像
    ports:
      - "8041:8041"                         # 宿主机端口:容器端口(供外部访问)
    env_file:
      - .env                                # 从 .env 文件加载环境变量(数据库密码等)
    environment:
      - TORNADO_ENV=production              # 运行环境设为生产模式
      - DB_HOST=mysql                       # 数据库地址指向 Docker 网络中的 mysql 服务
      - REDIS_HOST=redis                    # Redis 地址指向 Docker 网络中的 redis 服务
    volumes:
      - ./uploads:/data/apps/uploads        # 持久化上传文件到宿主机
      - ./logs:/data/apps/logs              # 持久化日志(与 Dockerfile WORKDIR 对应)
    depends_on:
      - mysql                               # 声明依赖,但不保证 mysql 已就绪
      - redis
    restart: unless-stopped                 # 除非手动停止,否则总是自动重启

  # ====================================================================
  # MySQL 数据库
  # ====================================================================
  mysql:
    image: mysql:8.0                        # 官方 MySQL 8.0 镜像
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}   # root 密码,从 .env 读取
      MYSQL_DATABASE: ${DB_DATABASE}        # 初始化时自动创建的数据库名
    ports:
      - "3306:3306"                         # 暴露到宿主机(生产环境建议去掉)
    volumes:
      - mysql_data:/var/lib/mysql           # 命名卷持久化数据库数据
    restart: unless-stopped

  # ====================================================================
  # Redis 缓存
  # ====================================================================
  redis:
    image: redis:7-alpine                   # 轻量级 Redis 7 镜像
    command: redis-server --requirepass ${REDIS_PASSWORD}  # 启动时设置访问密码
    ports:
      - "6379:6379"                         # 暴露到宿主机(生产环境建议去掉)
    volumes:
      - redis_data:/data                    # 持久化 Redis 数据
    restart: unless-stopped

# ======================================================================
# 命名卷:由 Docker 管理,数据存放在宿主机 /var/lib/docker/volumes 下
# ======================================================================
volumes:
  mysql_data:                               # MySQL 数据持久化卷
  redis_data:                               # Redis 数据持久化卷

完整版 .env 配置示例

使用完整版 docker-compose.yml 时,.env 文件中的数据库和 Redis 地址应指向 Docker 服务名称:

bash
# ============================================================
# 数据库配置(指向 Docker 网络中的 mysql 服务)
# ============================================================
DB_DRIVER=mysql
DB_HOST=mysql                    # Docker 服务名称,不是 127.0.0.1
DB_PORT=3306
DB_DATABASE=djangoadmin.tornado.antdvue
DB_USERNAME=root
DB_PASSWORD=your_mysql_password  # 与 MYSQL_ROOT_PASSWORD 一致
DB_PREFIX=tornado_

# ============================================================
# Redis 配置(指向 Docker 网络中的 redis 服务)
# ============================================================
REDIS_HOST=redis                 # Docker 服务名称,不是 127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_AUTH=True

# ============================================================
# JWT 配置(必填)
# ============================================================
JWT_SECRET=your_jwt_secret_key_at_least_32_bytes

# ============================================================
# 应用配置
# ============================================================
TORNADO_ENV=production
TORNADO_DEBUG=False

常用 Docker 命令

bash
# 构建镜像
docker compose build

# 启动服务(后台运行)
docker compose up -d

# 停止服务
docker compose down

# 停止服务并删除数据卷(⚠️ 会丢失数据)
docker compose down -v

# 查看日志(实时跟踪)
docker compose logs -f app

# 查看所有服务日志
docker compose logs -f

# 进入容器
docker compose exec app bash

# 重启服务
docker compose restart app

# 查看容器状态
docker compose ps

# 查看容器资源占用
docker stats

数据持久化

Docker Compose 使用命名卷和绑定挂载持久化数据:

存储方式卷名/路径说明
命名卷mysql_dataMySQL 数据文件(由 Docker 管理)
命名卷redis_dataRedis 数据文件(由 Docker 管理)
绑定挂载./uploads上传文件(映射到宿主机)
绑定挂载./logs日志文件(映射到宿主机)

数据备份

生产环境定期备份数据库:

bash
# 备份 MySQL
docker compose exec mysql mysqldump -uroot -p${DB_PASSWORD} ${DB_DATABASE} > backup_$(date +%Y%m%d).sql

# 恢复 MySQL
docker compose exec -T mysql mysql -uroot -p${DB_PASSWORD} ${DB_DATABASE} < backup.sql

生产环境部署建议

1. 关闭调试模式

bash
# .env
TORNADO_DEBUG=False
TORNADO_ENV=production

2. 使用强密钥

bash
# 生成 JWT 密钥
python -c "import secrets; print(secrets.token_urlsafe(48))"

3. 配置 Nginx 反向代理

nginx
server {
    # 监听 80 端口(HTTP)
    listen 80;

    # 域名配置(替换为实际域名)
    server_name your-domain.com;

    # 反向代理配置:将所有请求转发到 Tornado 应用
    location / {
        # 转发目标:Tornado 应用监听的地址和端口
        proxy_pass http://127.0.0.1:8041;

        # 传递原始请求头,让后端获取真实的客户端信息
        proxy_set_header Host $host;                          # 原始域名
        proxy_set_header X-Real-IP $remote_addr;              # 客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 代理链 IP 列表
        proxy_set_header X-Forwarded-Proto $scheme;           # 原始协议(http/https)

        # 超时配置(根据业务需求调整)
        proxy_connect_timeout 60s;    # 连接后端超时时间
        proxy_send_timeout 60s;       # 发送请求超时时间
        proxy_read_timeout 60s;       # 读取响应超时时间

        # 缓冲配置
        proxy_buffering on;           # 开启响应缓冲,减轻后端压力
        proxy_buffer_size 4k;         # 响应头缓冲区大小
        proxy_buffers 8 4k;           # 响应体缓冲区数量和大小
    }

    # 静态文件直接由 Nginx 提供(可选,提升性能)
    location /static/ {
        alias /data/apps/static/;     # 映射到容器内的静态文件目录
        expires 7d;                   # 浏览器缓存 7 天
        access_log off;               # 关闭静态文件访问日志
    }

    # 上传文件直接由 Nginx 提供(可选)
    location /uploads/ {
        alias /data/apps/uploads/;    # 映射到容器内的上传文件目录
        expires 1d;                   # 浏览器缓存 1 天
        access_log off;
    }

    # 安全配置:拒绝访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

HTTPS 配置

生产环境建议启用 HTTPS。可使用 Let's Encrypt 免费证书:

bash
# 安装 certbot
apt install certbot python3-certbot-nginx

# 申请证书并自动配置 Nginx
certbot --nginx -d your-domain.com

4. 限制端口暴露

生产环境建议不暴露 MySQL 和 Redis 端口到宿主机:

yaml
# docker-compose.yml
mysql:
  # ports:           # 注释掉或删除
  #   - "3306:3306"  # 生产环境不暴露
  ...

redis:
  # ports:           # 注释掉或删除
  #   - "6379:6379"  # 生产环境不暴露
  ...

5. 配置日志轮转

yaml
# docker-compose.yml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "500m"    # 单个日志文件最大 500MB
        max-file: "10"      # 最多保留 10 个日志文件

常见问题

容器启动失败

bash
# 查看容器日志
docker compose logs app

# 常见原因:
# 1. .env 配置错误(数据库密码、Redis 密码)
# 2. 端口被占用(修改 docker-compose.yml 中的端口映射)
# 3. 磁盘空间不足
# 4. JWT_SECRET 未配置或过短

数据库连接失败

1. 确认 MySQL 容器已启动:docker compose ps
2. 确认 .env 中 DB_HOST=mysql(Docker 服务名称,不是 127.0.0.1)
3. 确认 DB_PASSWORD 与 MYSQL_ROOT_PASSWORD 一致
4. 确认 MySQL 已就绪:docker compose logs mysql

Redis 连接失败

1. 确认 Redis 容器已启动:docker compose ps
2. 确认 .env 中 REDIS_HOST=redis(Docker 服务名称,不是 127.0.0.1)
3. 确认 REDIS_PASSWORD 与 docker-compose.yml 中的密码一致

容器内时区不对

Dockerfile 已设置 TZ=Asia/Shanghai,如果仍有时区问题:

bash
# 进入容器检查时区
docker compose exec app date

# 手动设置时区(docker-compose.yml)
environment:
  - TZ=Asia/Shanghai

总结

Docker 部署通过 Docker Compose 一键启动应用、MySQL、Redis 三个服务。多阶段构建减小镜像体积,命名卷保证数据持久化。生产环境建议关闭调试模式、使用强密钥、配置 Nginx 反向代理、限制端口暴露、配置日志轮转。

小蚂蚁云团队 · 提供技术支持