Files
djangoadmin-wiki/DjangoAdmin_Tornado_NaiveVue/zh/volume1/docker.md
T
2026-09-16 17:25:03 +08:00

517 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_naivevue:
image: tornado_naivevue:latest # 镜像名称
container_name: tornado_naivevue # 容器名称
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.naivevue
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 反向代理、限制端口暴露、配置日志轮转。