Files

242 lines
9.3 KiB
Markdown
Raw Permalink Normal View History

2026-09-21 17:11:35 +08:00
# 学生管理系统 Docker 部署说明
> 本次部署已在你的机器上实际执行并验证通过:
> MySQL、后端、前端三个容器均正常启动,浏览器访问 `http://localhost` 可用。
> 下方命令可直接复制执行。
## 一、部署架构
```
浏览器
│ http://localhost
▼
┌────────────────────────────────┐
│ frontend (node:20 → nginx:1.25) │ 静态文件 /usr/share/nginx/html
└───────────┬────────────────────┘
│ 反向代理(vue/nginx.conf 中已配置)
│ /login /student /files ... → http://backend:9090
▼
┌────────────────────────────────┐
│ backend (python:3.11-slim) │ uvicorn main:app :9090
│ files/ 挂载到宿主机持久化
└───────────┬────────────────────┘
│ aiomysql,DB_HOST=mysql
▼
┌────────────────────────────────┐
│ mysql (mysql:8.0) │ volume: student_mysql_data
│ 库 student_system,启动时自动建表
└────────────────────────────────┘
```
## 二、本次新增的文件
| 文件 | 作用 |
|------|------|
| `student_system_2/docker-compose.yml` | 编排 mysql + backend + frontend 三个服务 |
| `student_system_2/.env` | 实际生效的环境变量(已按你本机端口占用情况配置) |
| `student_system_2/.env.example` | 环境变量模板 |
| `student_system_2/fastapi-app/Dockerfile` | 后端镜像(Python 3.11 + uvicorn,暴露 9090) |
| `student_system_2/fastapi-app/.dockerignore` | 排除 `__pycache__`、虚拟环境等 |
| `student_system_2/vue/Dockerfile` | 前端镜像(Node 20 编译 → Nginx 托管) |
| `student_system_2/vue/.dockerignore` | 排除 `node_modules`、`dist`(关键:否则构建极慢) |
> `vue/nginx.conf` 是原有文件,直接复用,未做修改。其中代理目标写死为 `http://backend:9090`,
> 因此 compose 中后端服务名保持为 `backend`(已一致)。
**镜像地址与端口**
| 服务 | 镜像 | 容器名 | 宿主机端口 |
|------|------|--------|-----------|
| mysql | `mysql:8.0` | `student_system_2-mysql-1` | 13306 → 3306 |
| backend | `student-system-backend:latest` | `student_system_2-backend-1` | 9090 |
| frontend | `student-system-frontend:latest` | `student_system_2-frontend-1` | 80 |
## 三、环境准备
1. 安装 Docker Desktop(Windows/macOS)或 Docker Engine + Compose 插件(Linux)。
2. 验证:
```bash
docker --version
docker compose version
```
当前机器已确认:Docker 28.5.1 / Compose v2.40.2。
## 四、启动
在 `student_system_2` 目录(与 `docker-compose.yml` 同级)执行:
```bash
docker compose up -d --build
```
**启动顺序**由 `depends_on` 控制:MySQL 健康检查通过 → 启动 backend → 启动 frontend。
后端启动时自动建表(代码中 `generate_schemas=True`),无需手动执行迁移,已实测生成
`admin / clazz / course / grade / major / notice / student / student_course` 八张表。
查看状态:
```bash
docker compose ps # 等待 backend、mysql 显示 (healthy)
docker compose logs -f # Ctrl+C 退出,不影响容器运行
```
## 五、访问与验证
| 地址 | 说明 |
|------|------|
| http://localhost | 前端页面(登录/注册) |
| http://localhost:9090/docs | 后端 Swagger 文档 |
| http://localhost:9090/ | 后端根路径 |
| localhost:13306 | MySQL(Navicat/DBeaver 可连,root / 123456) |
## 六、日常运维命令
```bash
# 停止容器(保留数据)
docker compose stop
# 停止并删除容器与网络(数据卷保留,MySQL 数据不丢)
docker compose down
# 改完代码后重新构建并启动
docker compose up -d --build
# 只重启某个服务
docker compose restart backend
# 查看日志
docker compose logs -f backend
# 进入后端容器
docker compose exec backend bash
# 进入 MySQL 命令行
docker compose exec mysql mysql -uroot -p123456
# 查看资源占用
docker stats
```
> 说明:compose 未固定 `container_name`,容器名带项目前缀(`student_system_2-xxx-1`)。
> 因此请使用 `docker compose exec <服务名>` 而不是 `docker exec <容器名>`,更稳妥。
## 七、端口配置
你本机的 **3306 已被本地 MySQL 占用**(PID 6724),因此 `.env` 中已把容器内 3306 映射到宿主机 **13306**:
```ini
# student_system_2/.env
DB_NAME=student_system
DB_USER=root
DB_PASSWORD=123456
MYSQL_HOST_PORT=13306 # 容器内 3306 → 宿主机 13306
BACKEND_HOST_PORT=9090
FRONTEND_HOST_PORT=80 # 浏览器访问 http://localhost
```
修改端口后重新执行 `docker compose up -d` 即可生效。
## 八、数据持久化与备份
| 数据 | 位置 | 说明 |
|------|------|------|
| MySQL 数据 | Docker volume `student_mysql_data` | 删除容器不丢,`docker compose down -v` 才会清除 |
| 上传的文件 | 宿主机 `fastapi-app/files/` | 与容器 `/app/files` 双向同步 |
```bash
# 备份数据库到当前目录
docker compose exec -T mysql mysqldump -uroot -p123456 student_system > backup.sql
# 从备份恢复
docker compose exec -T mysql mysql -uroot -p123456 student_system < backup.sql
# 查看数据卷明细
docker volume inspect student_mysql_data
```
## 九、旧部署遗留容器与数据迁移(重要)
你机器上还存在 **旧目录名 `student_system` 时期**部署的三个已停止容器,
它们的数据卷是独立保存的,**本次部署没有删除或覆盖它们**:
| 遗留对象 | 说明 |
|---------|------|
| 容器 `student-mysql` / `student-backend` / `student-frontend` | 均已 Exited |
| 卷 `student_system_mysql_data` | 旧 MySQL 数据 |
| 卷 `student_system_upload_files` | 旧上传文件 |
新部署的数据库是**全新的空库**(表结构已自动创建,但无数据)。
**如果不需要旧数据**,可以清理掉这些遗留对象:
```bash
docker rm -f student-mysql student-backend student-frontend
docker volume rm student_system_mysql_data student_system_upload_files
docker rmi student_system-frontend student_system-backend
```
**如果需要把旧数据迁移过来**(旧部署用的同样是 root / 123456):
```bash
# 1) 用旧数据卷启动一个临时 MySQL(端口 13307,避免冲突)
docker run -d --name mysql-old -p 13307:3306 -e MYSQL_ROOT_PASSWORD=123456 ^
-v student_system_mysql_data:/var/lib/mysql mysql:8.0
# 2) 等 30 秒左右待其就绪,导出旧数据
docker exec mysql-old mysqldump -uroot -p123456 student_system > old_data.sql
# 3) 导入到新库
docker compose exec -T mysql mysql -uroot -p123456 student_system < old_data.sql
# 4) 清理临时容器
docker rm -f mysql-old
```
> Windows CMD 下换行符用 `^`;PowerShell 下请写成一行。
## 十、常见问题排查
**1. 前端页面打开报 502 / 接口失败**
- 检查:`docker compose ps`、`docker compose logs backend`
- 确认 `backend` 与 `frontend` 同处 `student-net` 网络(compose 已配置)
- 确认 nginx 代理目标仍为 `http://backend:9090`
**2. 后端日志报 `Can't connect to MySQL server`**
- MySQL 首次初始化较慢,等其变为 `healthy` 后会自动重连;必要时 `docker compose restart backend`
- 确认 `DB_HOST=mysql`(不能写 `localhost`,那是容器自身)
- 确认 `.env` 中 `DB_PASSWORD` 与 `MYSQL_ROOT_PASSWORD` 一致
**3. 后端报 `Unknown database 'student_system'`**
- 只有**首次**创建容器时才执行 `MYSQL_DATABASE` 建库。若数据卷已有旧数据则不会重建:
```bash
docker compose exec mysql mysql -uroot -p123456 -e "CREATE DATABASE IF NOT EXISTS student_system DEFAULT CHARSET utf8mb4;"
```
**4. 端口被占用 `Only one usage of each socket address` / `port is already allocated`**
- 按第七节修改 `.env` 中的端口后重新 `docker compose up -d`
- 查占用:`netstat -ano | findstr :3306`
**5. 前端构建很慢或 `npm ci` 失败**
- 确保 `vue/.dockerignore` 含 `node_modules/`(否则会把本机依赖打进构建上下文)
- 若 `package-lock.json` 与 `package.json` 不匹配,Dockerfile 已自动回退为 `npm install`
- 换源构建:`docker build --build-arg NPM_REGISTRY=https://registry.npmjs.org ./vue`
**6. 上传图片后访问 404**
- 确认宿主机 `fastapi-app/files` 目录存在且可写,映射路径为容器 `/app/files`
**7. pip 安装慢**
- Dockerfile 默认使用清华源,可换源:`docker build --build-arg PIP_INDEX_URL=https://pypi.org/simple ./fastapi-app`
## 十一、生产环境建议
1. **修改默认密码**:务必修改 `.env` 中的 `DB_PASSWORD`,不要用 `123456`。
2. **关闭 SQL 日志**:把 `fastapi-app/settings.py` 中 `"echo": True` 改为 `False`,避免大量 SQL 日志拖慢性能。
3. **不对宿主机暴露数据库**:删除 compose 中 `mysql` 的 `ports` 映射(后端走内部网络即可)。
4. **收敛 CORS**:`main.py` 中 `allow_origins=["*"]` 建议改为实际前端域名。
5. **启用 HTTPS**:在 nginx 中增加 443 监听并配置证书。
6. **限制日志体积**:为各服务增加 `logging.options.max-size` / `max-file`。