# Docker 快速部署 本章节介绍如何使用 Docker 快速部署后端服务,无需手动安装 Python、MySQL、Redis 等环境。 :::tip 温馨提示 Docker 部署适合快速体验和生产环境。本地开发建议使用 [后端启动](/zh/volume1/backend) 章节的方式。 ::: ## 前置条件 确保已安装 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 密钥等 ``` :::danger 重要提示 Docker 部署时,`.env` 中的 `DB_HOST` 和 `REDIS_HOST` 应指向 Docker 网络中的服务名称(如 `mysql`、`redis`),而非 `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_elevue: image: tornado_elevue:latest # 镜像名称 container_name: tornado_elevue # 容器名称 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.elevue 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_data` | MySQL 数据文件(由 Docker 管理) | | 命名卷 | `redis_data` | Redis 数据文件(由 Docker 管理) | | 绑定挂载 | `./uploads` | 上传文件(映射到宿主机) | | 绑定挂载 | `./logs` | 日志文件(映射到宿主机) | :::warning 数据备份 生产环境定期备份数据库: ```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; } } ``` :::tip 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 反向代理、限制端口暴露、配置日志轮转。