提交 c3417d53 authored 作者: 陈泽健's avatar 陈泽健

docs(deploy): 新增容器化部署Volume挂载优化需求文档和执行计划文档

变更内容:
- 修正 CreateCMD 本地路径 E:\GithubData → E:\github
- 修复 package-lock.json 中依赖的 peer 标记
- 新增部署运维 PRD 需求文档和计划执行文档
- 补充部署方案文档至版本控制
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 561591ef
@echo off @echo off
cd /d E:\GithubData\ubains-module-test\platform-auto-test cd /d E:\github\ubains-module-test\platform-auto-test
E:\nodejs\claude.cmd --permission-mode bypassPermissions E:\nodejs\claude.cmd --permission-mode bypassPermissions
# 容器化部署优化:Volume 挂载免重建镜像 需求文档
> **文档版本**: v1.0
> **创建日期**: 2026-07-27
> **文档状态**: 初稿待评审
> **负责人**: czj
---
## 一、背景
### 1.1 问题描述
当前 `platform-auto-test` 平台已通过 Docker 容器化部署在服务器 `192.168.5.60` 上,部署配置位于 `deploy/` 目录。但现有部署方式存在以下问题:
1. **代码更新需重建镜像**:Dockerfile 使用 `COPY` 将代码打包进镜像,每次修改 Python/Vue 代码后,必须执行 `docker compose build` 重新构建镜像,构建过程耗时 3-5 分钟
2. **频繁构建影响效率**:开发迭代阶段修改频繁,每次构建浪费大量时间
3. **与另一维护服务冲突风险**:当前代码在 `~/ubains-module-test/` git 目录下,与另一个维护平台(8088 端口)共用同一仓库,存在分支冲突风险
### 1.2 当前部署架构
```
服务器 192.168.5.60
├── ~/ubains-module-test/ ← git 仓库(与另一服务共用)
│ ├── deploy/ ← 部署配置
│ │ ├── docker-compose.yml ← 代码 COPY 进镜像
│ │ ├── Dockerfile.backend ← 代码 COPY 进镜像
│ │ └── Dockerfile.frontend ← 代码 COPY 进镜像
│ └── data/ ← 数据库持久化(空库)
└── /opt/troubleshoot/ ← 另一维护平台(8088 端口,不受影响)
```
### 1.3 目标
1. **独立目录部署**:将本平台部署到独立目录 `/opt/plat-auto-test/`,与另一服务完全隔离
2. **Volume 挂载代码**:后端代码通过 volume 挂载,改代码只需重启容器,无需重建镜像
3. **前端构建产物挂载**:前端 `dist/` 通过 volume 挂载,更新只需上传新构建产物
4. **数据库迁移**:将本地有数据的 `test_platform.db`(241 个 UI 用例)迁移到服务器新目录
---
## 二、需求内容
### 2.1 功能需求
#### 2.1.1 独立目录结构
```
/opt/plat-auto-test/ ← 独立部署目录(无 git,与另一服务完全隔离)
├── deploy/ ← 部署配置文件(Dockerfile、Compose、Nginx)
│ ├── docker-compose.yml
│ ├── Dockerfile.backend
│ ├── Dockerfile.frontend
│ └── nginx/default.conf
├── backend/ ← 后端源码(volume 挂载到容器)
│ ├── app/
│ ├── scripts/
│ └── requirements.txt
├── frontend/
│ └── dist/ ← 前端构建产物(volume 挂载到容器)
└── data/ ← 数据持久化
├── test_platform.db ← 有数据的数据库(241个UI用例)
├── screenshots/
└── reports/
```
#### 2.1.2 Volume 挂载方案
| 容器 | 镜像内容 | Volume 挂载 | 更新方式 |
|------|---------|-------------|---------|
| 后端 | Python 3.10 + Playwright + pip 依赖 | `backend/``/app/` | 上传代码 → `docker compose restart backend` |
| 前端 | nginx:alpine | `frontend/dist/``/usr/share/nginx/html` | 本地构建 → 上传 dist/ → `docker compose restart frontend` |
#### 2.1.3 更新流程对比
| 场景 | 当前方式(COPY 进镜像) | 优化后(Volume 挂载) |
|------|----------------------|---------------------|
| 改后端代码 | 上传代码 → 重建镜像(3-5min) → 重启 | 上传代码 → 重启容器(5s) |
| 改前端代码 | 本地构建 → 上传 → 重建镜像(3-5min) → 重启 | 本地构建 → 上传 dist/ → 重启容器(5s) |
| 更新数据库 | 上传 .db 文件 → 重启容器 | 上传 .db 文件 → 重启容器(不变) |
| 改配置(nginx/yml) | 上传 → 重建镜像 → 重启 | 上传 → 重启容器 |
### 2.2 非功能需求
#### 2.2.1 性能要求
- 后端容器重启时间 < 10 秒
- 前端容器重启时间 < 5 秒
- 首次部署总时间(含构建)< 15 分钟
#### 2.2.2 安全要求
- 独立目录不与另一服务共享
- 数据库文件权限设为 644(容器可读写)
- 避免将整个 backend 目录挂载到容器中的敏感路径
---
## 三、方案设计
### 3.1 后端 Dockerfile 改造
**改造前**:代码 COPY 进镜像,镜像体积大,代码更新需重建
```dockerfile
COPY backend/ .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
```
**改造后**:镜像只装依赖,代码从 volume 挂载
```dockerfile
# 只复制 requirements.txt 并安装依赖
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 安装 Playwright Chromium
RUN playwright install chromium
# 不复制代码 —— 启动时从 volume 挂载
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
```
### 3.2 前端 Dockerfile 改造
**改造前**:镜像内包含构建产物,更新需重建
```dockerfile
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
```
**改造后**:镜像只含 nginx 配置,构建产物从 volume 挂载
```dockerfile
FROM nginx:alpine
# 只复制 nginx 配置(不变的部分)
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
# 不复制 dist/ —— 启动时从 volume 挂载
```
### 3.3 docker-compose.yml 改造
**改造前**
```yaml
services:
backend:
volumes:
- ../data:/app/data # 只挂载数据库
frontend:
# 无 volume 挂载
```
**改造后**
```yaml
services:
backend:
volumes:
- /opt/plat-auto-test/data:/app/data
- /opt/plat-auto-test/backend:/app # 新增:挂载后端代码
frontend:
volumes:
- /opt/plat-auto-test/frontend/dist:/usr/share/nginx/html # 新增:挂载前端构建产物
```
---
## 四、验收标准
### 4.1 功能验收
| 验收项 | 验收标准 |
|--------|---------|
| 独立目录部署 | 服务在 `/opt/plat-auto-test/` 下正常运行 |
| 后端 volume 挂载 | 修改后端代码后重启容器,新代码生效 |
| 前端 volume 挂载 | 上传新构建产物后重启容器,新前端生效 |
| 数据库迁移 | 访问平台可看到 241 个 UI 用例 |
| 已有服务不受影响 | 8088 端口服务继续正常运行 |
### 4.2 性能验收
| 验收项 | 验收标准 |
|--------|---------|
| 后端重启时间 | 从执行命令到服务可用 < 10 秒 |
| 后端健康检查 | `curl http://localhost:8001/health` 返回 200 |
| 前端可访问 | `curl http://localhost/` 返回 200 |
---
## 五、风险评估
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| 后端代码路径不一致 | 中 | 高 | 确保容器内路径 `/app` 与挂载路径匹配 |
| Python 依赖未安装 | 低 | 高 | 首次构建时确保 requirements.txt 安装完整 |
| 前端构建产物不完整 | 低 | 中 | 本地 `npm run build` 成功后上传 |
| 数据库文件权限问题 | 中 | 中 | 容器内 uid 1000 需有读写权限 |
| 旧容器未停止导致端口冲突 | 低 | 中 | 先停旧容器再启动新容器 |
---
## 六、附录
### 6.1 相关文档
| 文档 | 说明 |
|------|------|
| `Docs/部署方案/Linux服务器部署方案.md` | 原始部署方案 |
| `Docs/部署方案/Linux容器化部署_执行计划.md` | 原始部署执行计划 |
| `deploy/docker-compose.yml` | 主编排文件 |
| `deploy/Dockerfile.backend` | 后端 Dockerfile |
| `deploy/Dockerfile.frontend` | 前端 Dockerfile |
| `deploy/nginx/default.conf` | Nginx 配置 |
| `HANDOFF_UI自动化.md` | 项目交接文档 |
### 6.2 服务器信息
| 项目 | 值 |
|------|-----|
| 服务器 | 192.168.5.60 |
| 用户 | ubains |
| 操作系统 | Ubuntu 26.04 LTS |
| 已有服务 | `/opt/troubleshoot/` → 端口 8088 |
| 新部署目录 | `/opt/plat-auto-test/` |
| 新服务端口 | 80(前端)、8001(后端) |
\ No newline at end of file
# 执行计划:容器化部署 Volume 挂载优化
> **文档状态**: 初稿待评审
> **编写日期**: 2026-07-27
> **当前分支**: `platform-auto-test`
> **目标服务器**: 192.168.5.60 / Ubuntu 26.04 LTS / 用户 ubains
> **关联 PRD**: `_PRD_需求文档_容器化部署Volume挂载优化.md` v1.0
> **预计工时**: 1 天
---
## 一、执行概述
### 1.1 任务背景
当前容器化部署在 `~/ubains-module-test/` git 目录下,代码通过 `COPY` 打包进镜像,每次更新代码需重建镜像(3-5分钟)。同时该 git 目录与另一个维护平台(8088 端口)共用,存在冲突风险。
### 1.2 执行目标
| 目标 | 描述 | 验收标准 |
|------|------|---------|
| 独立目录部署 | 将服务迁移到 `/opt/plat-auto-test/` | 服务在新目录正常运行 |
| Volume 挂载代码 | 后端代码通过 volume 挂载,改代码无需重建 | 修改代码后重启生效 |
| 前端产物挂载 | 前端构建产物通过 volume 挂载 | 上传新 dist/ 后重启生效 |
| 数据库迁移 | 将本地有数据的库迁移到服务器 | 访问平台看到 241 个 UI 用例 |
| 服务隔离 | 与另一维护平台完全独立 | 8088 端口服务不受影响 |
### 1.3 预计工期
| 阶段 | 内容 | 预计时间 |
|------|------|---------|
| Phase 1 | 本地部署配置改造 | 0.5 天 |
| Phase 2 | 服务器迁移部署 | 0.5 天 |
| Phase 3 | 数据迁移与验证 | 0.5 天 |
| **总计** | | **1.5 天** |
---
## 二、任务分解与实施计划
### Phase 1: 本地部署配置改造(0.5 天)
#### 1.1 修改 Dockerfile.backend — 去掉代码 COPY
**目标**:镜像只装依赖,不打包代码
**文件**: `deploy/Dockerfile.backend`
**变更**
```dockerfile
# 改造前:COPY 了整个后端代码
COPY backend/ .
# 改造后:不复制代码,启动时从 volume 挂载
# 删掉这一行 COPY backend/ .
```
**完整改造后 Dockerfile.backend**
```dockerfile
FROM python:3.10-slim
WORKDIR /app
# 安装 Playwright 系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
wget gnupg curl libnss3 libnspr4 libatk1.0-0t64 \
libatk-bridge2.0-0t64 libcups2t64 libdrm2 libdbus-1-3 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2t64 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖(使用国内镜像源)
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple \
--trusted-host pypi.tuna.tsinghua.edu.cn --retries 5 --timeout 120 -r requirements.txt
# 安装 Playwright Chromium
RUN playwright install chromium
# 创建数据目录
RUN mkdir -p /app/data/screenshots /app/data/reports
EXPOSE 8001
# 注意:代码通过 volume 挂载,不 COPY
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
```
#### 1.2 修改 Dockerfile.frontend — 去掉 dist COPY
**目标**:镜像只含 nginx 配置,构建产物从 volume 挂载
**文件**: `deploy/Dockerfile.frontend`
**变更**
```dockerfile
# 改造前:多阶段构建,COPY 了 dist/
FROM node:20-alpine AS build
COPY frontend/ .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
# 改造后:纯 nginx 镜像,只复制配置
FROM nginx:alpine
# 复制 Nginx 配置
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
# 不复制 dist/ —— 启动时从 volume 挂载
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
#### 1.3 修改 docker-compose.yml — 添加 volume 挂载
**文件**: `deploy/docker-compose.yml`
**变更**
```yaml
services:
backend:
# ... 保持不变 ...
volumes:
- /opt/plat-auto-test/data:/app/data
- /opt/plat-auto-test/backend:/app # 新增:挂载后端代码
# ... 保持不变 ...
frontend:
# ... 保持不变 ...
volumes:
- /opt/plat-auto-test/frontend/dist:/usr/share/nginx/html # 新增:挂载前端构建产物
# ... 保持不变 ...
```
#### 1.4 修改 deploy.sh — 适配新目录
**文件**: `deploy/deploy.sh`
**变更**:将默认路径从 `~/ubains-module-test` 改为 `/opt/plat-auto-test`
---
### Phase 2: 服务器迁移部署(0.5 天)
#### 2.1 停掉当前容器
```bash
ssh ubains@192.168.5.60
cd ~/ubains-module-test/deploy
docker compose down
```
#### 2.2 创建独立目录
```bash
sudo mkdir -p /opt/plat-auto-test/deploy/nginx
sudo mkdir -p /opt/plat-auto-test/backend
sudo mkdir -p /opt/plat-auto-test/frontend/dist
sudo mkdir -p /opt/plat-auto-test/data/screenshots
sudo mkdir -p /opt/plat-auto-test/data/reports
sudo chown -R ubains:ubains /opt/plat-auto-test
```
#### 2.3 上传部署配置
从本地上传以下文件到 `/opt/plat-auto-test/deploy/`
| 文件 | 本地路径 | 服务器路径 |
|------|---------|-----------|
| docker-compose.yml | `deploy/docker-compose.yml` | `/opt/plat-auto-test/deploy/` |
| Dockerfile.backend | `deploy/Dockerfile.backend` | `/opt/plat-auto-test/deploy/` |
| Dockerfile.frontend | `deploy/Dockerfile.frontend` | `/opt/plat-auto-test/deploy/` |
| nginx/default.conf | `deploy/nginx/default.conf` | `/opt/plat-auto-test/deploy/nginx/` |
#### 2.4 上传后端代码
```bash
# 本地打包
cd E:\github\ubains-module-test\platform-auto-test
# 上传 backend/ 目录(排除 pycache)
scp -r backend/ ubains@192.168.5.60:/opt/plat-auto-test/backend/
```
#### 2.5 构建前端并上传
```bash
# 本地构建前端
cd frontend
npm run build
# 上传构建产物
scp -r dist/* ubains@192.168.5.60:/opt/plat-auto-test/frontend/dist/
```
#### 2.6 构建镜像并启动
```bash
cd /opt/plat-auto-test/deploy
# 首次需要构建镜像(只这一次)
docker compose build
# 启动服务
docker compose up -d
# 检查健康状态
docker compose ps
curl http://localhost:8001/health
curl http://localhost/
```
---
### Phase 3: 数据迁移与验证(0.5 天)
#### 3.1 上传有数据的数据库
```bash
# 本地:上传有数据的数据库到服务器
scp E:\github\ubains-module-test\platform-auto-test\backend\data\test_platform.db \
ubains@192.168.5.60:/opt/plat-auto-test/data/test_platform.db
```
#### 3.2 重启后端
```bash
ssh ubains@192.168.5.60
cd /opt/plat-auto-test/deploy
docker compose restart backend
```
#### 3.3 验证数据
```bash
# 检查 API 返回用例数
curl -s "http://localhost:8001/api/cases?limit=10" | python3 -m json.tool | head -20
# 检查模块
curl -s "http://localhost:8001/api/modules?case_type=ui" | python3 -c "
import sys,json
d=json.load(sys.stdin)
print(f'UI模块数: {len(d)}')
"
```
#### 3.4 验证前端可访问
```bash
curl -s -o /dev/null -w "%{http_code}" http://localhost/
# 期望输出: 200
```
#### 3.5 验证已有服务不受影响
```bash
curl -s -o /dev/null -w "%{http_code}" http://localhost:8088/
# 期望输出: 200
```
---
## 三、更新操作指南(后续日常用)
### 改后端代码后
```bash
# 本地改完代码后,上传到服务器
scp -r backend/ ubains@192.168.5.60:/opt/plat-auto-test/backend/
# SSH 到服务器,重启容器
ssh ubains@192.168.5.60
cd /opt/plat-auto-test/deploy
docker compose restart backend
```
### 改前端代码后
```bash
# 本地改完代码后,构建并上传
cd frontend
npm run build
scp -r dist/* ubains@192.168.5.60:/opt/plat-auto-test/frontend/dist/
# SSH 到服务器,重启容器
ssh ubains@192.168.5.60
cd /opt/plat-auto-test/deploy
docker compose restart frontend
```
### 更新数据库
```bash
# 上传新的数据库文件
scp backend/data/test_platform.db ubains@192.168.5.60:/opt/plat-auto-test/data/
# 重启后端
ssh ubains@192.168.5.60
cd /opt/plat-auto-test/deploy
docker compose restart backend
```
---
## 四、验收标准
### 4.1 功能验收
| 验收项 | 操作 | 期望结果 |
|--------|------|---------|
| 独立目录运行 | 检查容器挂载 | `/opt/plat-auto-test/` 下所有文件完整 |
| 后端 volume 挂载 | 修改一个 Python 文件后重启 | 新代码生效 |
| 前端 volume 挂载 | 更新 dist/ 后重启 | 新前端生效 |
| 数据库数据完整 | 访问 API 查用例数 | 返回 241 个 UI 用例 |
| 服务隔离 | 访问 8088 端口 | 另一维护平台正常运行 |
### 4.2 性能验收
| 验收项 | 标准 |
|--------|------|
| 后端重启时间 | < 10 秒 |
| 健康检查 | HTTP 200 |
| 前端首页 | HTTP 200 |
---
## 五、风险评估
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| 容器内路径 `/app` 与挂载冲突 | 中 | 高 | 确保 WORKDIR 和 volume 路径一致 |
| 旧容器未完全停止 | 低 | 中 | 先 `docker compose down` 再启动 |
| 数据库文件权限不足 | 中 | 高 | 设置 `chmod 644` 并用 `chown` 给容器用户 |
| 前端构建产物路径不对 | 低 | 中 | 确认 nginx root 指向 `/usr/share/nginx/html` |
| 忘记上传 backend/ 代码 | 低 | 高 | 启动时检查 `uvicorn` 能否找到 app.main |
---
## 六、实施记录
| 日期 | 操作 | 负责人 | 备注 |
|------|------|--------|------|
| 2026-07-27 | 编写需求文档和计划执行文档 | czj | 待实施 |
---
## 七、后续工作
| 优先级 | 待办 | 说明 |
|--------|------|------|
| P1 | 实施迁移部署 | 按 Phase 2 步骤执行 |
| P2 | 数据库迁移 | 上传有数据的 .db 文件 |
| P3 | 全量执行验证 | 迁移后执行 241 个用例验证 |
| P4 | 编写自动化更新脚本 | 简化后续更新操作 |
---
## 八、附录
### 8.1 相关文件
| 文件 | 路径 |
|------|------|
| 需求文档 | `Docs/PRD/需求文档/部署运维/_PRD_需求文档_容器化部署Volume挂载优化.md` |
| 部署方案 | `Docs/部署方案/Linux服务器部署方案.md` |
| 原始部署执行计划 | `Docs/部署方案/Linux容器化部署_执行计划.md` |
| 后端 Dockerfile | `deploy/Dockerfile.backend` |
| 前端 Dockerfile | `deploy/Dockerfile.frontend` |
| Docker Compose | `deploy/docker-compose.yml` |
| Nginx 配置 | `deploy/nginx/default.conf` |
| 部署脚本 | `deploy/deploy.sh` |
### 8.2 服务器信息
| 项目 | 值 |
|------|-----|
| 服务器 IP | 192.168.5.60 |
| SSH 用户 | ubains |
| 操作系统 | Ubuntu 26.04 LTS |
| 已有服务 | 8088 端口(`/opt/troubleshoot/`) |
| 新部署目录 | `/opt/plat-auto-test/` |
| 前端地址 | http://192.168.5.60 |
| API 文档 | http://192.168.5.60:8001/docs |
\ No newline at end of file
# 执行计划:容器化部署(Docker + Linux)
> **文档状态**: 已确认服务器环境,计划可执行
> **编写日期**: 2026-07-27
> **当前分支**: `platform-auto-test`
> **目标服务器**: 192.168.5.60 / Ubuntu 26.04 LTS / 用户 ubains
> **前置文档**: `Docs/部署方案/Linux服务器部署方案.md`
> **预计工时**: 2 天
---
## 一、服务器环境确认
### 1.1 环境快照
| 项目 | 值 |
|------|-----|
| 操作系统 | Ubuntu 26.04 LTS (Resolute Raccoon) |
| 内核 | 最新 |
| 用户 | ubains (uid=1000, 有 sudo) |
| Python | 3.14.4 |
| **Docker** | ❌ 未安装 |
| **已有服务** | `/opt/troubleshoot/` → 端口 **8088**(Python Web 服务) |
| 可用端口 | 80 / 443 / 3000 / 8001 全部空闲 |
| 磁盘 | 34GB 总量,23GB 可用 |
| 内存 | 15GB,14GB 可用 |
### 1.2 端口分配
| 服务 | 端口 | 说明 |
|------|------|------|
| 已有故障排查平台 | **8088** | 保持不变,不受影响 |
| 本系统前端 (Nginx) | **80** | 容器内,宿主机映射 :80 |
| 本系统后端 (API) | **8001** | 容器内,宿主机不直接暴露 |
| 本系统后端调试 | **8001** | 仅容器内部访问,Nginx 反向代理 |
---
## 二、执行步骤
### Phase 0: 服务器 Docker 安装(新增)
**由于服务器未安装 Docker,需要先完成此步骤。**
#### 操作步骤
```bash
# 1. SSH 到服务器
ssh ubains@192.168.5.60
# 2. 安装 Docker(Ubuntu 官方源)
sudo apt-get update
sudo apt-get install -y docker.io docker-compose-v2
# 3. 将当前用户加入 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
# 4. 退出并重新登录使组生效
exit
ssh ubains@192.168.5.60
# 5. 验证安装
docker --version
docker compose version
docker run hello-world
```
**注意**
- Ubuntu 26.04 的包名是 `docker.io`(非 `docker-ce`
- Docker Compose v2 是 `docker-compose-v2` 包,命令为 `docker compose`
- 安装 Docker 不会影响 8088 端口的已有服务
---
### Phase 1: 后端 Dockerfile(0.5 天)
**目标**:构建可运行 Playwright 的后端镜像
#### 创建 `deploy/Dockerfile.backend`
```dockerfile
FROM python:3.10-slim
WORKDIR /app
# 安装 Playwright 系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
wget gnupg \
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libdbus-1-3 libxkbcommon0 \
libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
libgbm1 libpango-1.0-0 libcairo2 libasound2 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 安装 Chromium
RUN playwright install chromium
# 复制后端代码
COPY backend/ .
# 创建数据目录
RUN mkdir -p /app/data/screenshots /app/data/reports
EXPOSE 8001
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
```
**关键点**
- 使用 `python:3.10-slim`(服务器是 3.14,但容器内用 3.10 无影响)
- 15 个系统依赖库保证 Chromium 运行
- `--workers 1`(SQLite 不支持多 worker 并发)
---
### Phase 2: 前端 Dockerfile(0.5 天)
**目标**:多阶段构建,Nginx 托管静态文件
#### 创建 `deploy/Dockerfile.frontend`
```dockerfile
# ---- 构建阶段 ----
FROM node:20-alpine AS build
WORKDIR /app
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ .
RUN npm run build
# ---- 运行阶段 ----
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
**关键点**
- 构建产物 < 10MB,最终镜像约 25MB
- `npm ci` 保证可复现构建
- 前端 `baseURL: ''` 确保请求路径为 `/api/...`,由 Nginx 代理
---
### Phase 3: Nginx 配置(0.3 天)
#### 创建 `deploy/nginx/default.conf`
```nginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# SPA 路由
location / {
try_files $uri $uri/ /index.html;
}
# API 反向代理
location /api/ {
proxy_pass http://backend:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
# WebSocket 代理
location /api/executions/ws/ {
proxy_pass http://backend:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}
```
---
### Phase 4: Docker Compose 编排(0.3 天)
#### 创建 `deploy/docker-compose.yml`
```yaml
version: "3.8"
services:
backend:
build:
context: ..
dockerfile: deploy/Dockerfile.backend
container_name: plat-auto-test-backend
ports:
- "8001:8001"
volumes:
- ../data:/app/data
environment:
- DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
- PLAYWRIGHT_HEADLESS=true
- PLAYWRIGHT_TIMEOUT=30000
- LOG_LEVEL=INFO
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
frontend:
build:
context: ..
dockerfile: deploy/Dockerfile.frontend
container_name: plat-auto-test-frontend
ports:
- "80:80"
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
```
**关键点**
- `backend` 暴露 8001 端口(供调试用)
- `frontend` 暴露 80 端口作为统一入口
- 数据持久化:`../data` 挂载到容器 `/app/data`
- 健康检查确保后端就绪后才启动前端
- 容器名加 `plat-auto-test-` 前缀,避免与已有服务冲突
---
### Phase 5: 环境变量 + 部署脚本(0.3 天)
#### 创建 `deploy/.env.example`
```bash
DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
PLAYWRIGHT_HEADLESS=true
PLAYWRIGHT_TIMEOUT=30000
LOG_LEVEL=INFO
```
#### 创建 `deploy/deploy.sh`
```bash
#!/bin/bash
set -e
echo "=== 平台自动化测试系统 - Docker 部署 ==="
# 检查 Docker
if ! command -v docker &> /dev/null; then
echo "错误: Docker 未安装"
echo "请执行: sudo apt-get install -y docker.io docker-compose-v2"
exit 1
fi
# 创建数据目录
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
mkdir -p "$PROJECT_DIR/data/screenshots" "$PROJECT_DIR/data/reports"
echo "📦 构建镜像..."
cd "$SCRIPT_DIR"
docker compose build
echo "🚀 启动服务..."
docker compose up -d
echo "⏳ 等待服务就绪..."
sleep 10
# 健康检查
echo "🔍 检查后端健康..."
curl -s http://localhost:8001/health || echo "⚠️ 后端未响应"
# 检查前端
echo "🔍 检查前端..."
curl -s -o /dev/null -w "%{http_code}" http://localhost/ || echo "⚠️ 前端未响应"
echo ""
echo "✅ 部署完成!"
echo " 前端: http://192.168.5.60"
echo " API: http://192.168.5.60/api"
echo " Docs: http://192.168.5.60:8001/docs"
echo ""
echo "📋 日志: docker compose logs -f"
echo "🛑 停止: docker compose down"
echo "⚠️ 已有故障排查平台: http://192.168.5.60:8088(不受影响)"
```
---
### Phase 6: 验证测试(0.3 天)
#### 本地构建验证(Windows Docker Desktop)
| 测试项 | 命令 | 预期 |
|--------|------|------|
| 后端构建 | `docker compose build backend` | 无错误 |
| 前端构建 | `docker compose build frontend` | 无错误 |
| 启动 | `docker compose up -d` | 容器运行中 |
| 健康检查 | `curl localhost:8001/health` | `{"status":"healthy"}` |
| 前端 | 浏览器打开 `http://localhost` | 页面正常 |
| 已有服务 | `curl localhost:8088` | 不应受影响 |
#### 远程部署验证(Linux 服务器)
部署后 SSH 到服务器执行:
```bash
# 检查容器状态
docker ps
# 健康检查
curl http://localhost:8001/health
# 前端
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost/
# 已有服务不受影响
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8088/
# 执行一个简单用例
curl -X POST http://localhost:8001/api/executions \
-H "Content-Type: application/json" \
-d '{"case_ids": ["一个测试用例ID"], "mode": "sequential"}'
```
---
## 三、文件清单
```
platform-auto-test/
├── deploy/ # 新建
│ ├── Dockerfile.backend # Phase 1
│ ├── Dockerfile.frontend # Phase 2
│ ├── nginx/
│ │ └── default.conf # Phase 3
│ ├── docker-compose.yml # Phase 4
│ ├── .env.example # Phase 5
│ └── deploy.sh # Phase 5
├── backend/ # 不变
├── frontend/ # 不变
└── data/ # 持久化目录(gitignored)
├── test_platform.db
├── screenshots/
└── reports/
```
---
## 四、风险与应对
| 风险 | 影响 | 应对 |
|------|------|------|
| ❌ Docker 未安装 | 无法部署 | Phase 0 先安装 Docker |
| 🔴 已有服务 8088 端口冲突 | 服务不可用 | 本系统只用 80/8001,无冲突 |
| 🔴 sudo 需要交互式密码 | 自动化脚本中断 | 部署脚本中避免 sudo 操作,或预先配置 sudo NOPASSWD |
| 🟡 SQLite 并发写入锁 | 批量执行失败 | `--workers 1` + 远期迁移 PostgreSQL |
| 🟡 容器内 Playwright 缺库 | 浏览器启动失败 | Dockerfile 已包含所有依赖 |
| 🟢 前端 API 404 | 页面不可用 | `baseURL: ''` 已确认,Nginx 代理路径已验证 |
---
## 五、验收标准
- [ ] `docker compose build` 无错误
- [ ] `docker compose up -d` 后服务 30s 内就绪
- [ ] 浏览器访问 `http://192.168.5.60` 正常显示前端
- [ ] API 正常响应,WebSocket 正常推送
- [ ] 执行一个 UI 测试用例成功
- [ ] 已有故障排查平台 `http://192.168.5.60:8088` 不受影响
- [ ] 容器重启后数据不丢失
---
## 六、时间线
| 阶段 | 内容 | 工时 | 依赖 |
|------|------|------|------|
| **Phase 0** | 安装 Docker(需手动执行) | 0.2 天 | 服务器 SSH |
| **Phase 1** | 后端 Dockerfile | 0.5 天 | - |
| **Phase 2** | 前端 Dockerfile | 0.5 天 | - |
| **Phase 3** | Nginx 配置 | 0.3 天 | - |
| **Phase 4** | Docker Compose | 0.3 天 | Phase 1-3 |
| **Phase 5** | 部署脚本 | 0.3 天 | Phase 4 |
| **Phase 6** | 验证测试 | 0.3 天 | Phase 0-5 |
| **合计** | | **2.4 天** | |
---
*本文档由 Claude Code 生成,已确认服务器环境(Ubuntu 26.04 / 无 Docker / 已有服务 8088 端口)。*
\ No newline at end of file
# Linux 服务器部署方案
> **文档状态**: 初稿
> **适用版本**: v1.0.0
> **编写日期**: 2026-07-27
> **目标系统**: CentOS 7+ / Ubuntu 20.04+ / 任何 Linux 发行版
---
## 目录
1. [方案对比](#1-方案对比)
2. [方案一:Docker 容器化部署(推荐)](#2-方案一docker-容器化部署推荐)
3. [方案二:裸机部署(传统方式)](#3-方案二裸机部署传统方式)
4. [部署前改造清单](#4-部署前改造清单)
5. [CI/CD 集成](#5-cicd-集成)
6. [运维与监控](#6-运维与监控)
7. [常见问题](#7-常见问题)
8. [附录:脚本模板](#8-附录脚本模板)
---
## 1. 方案对比
| 维度 | Docker 部署(推荐) | 裸机部署 |
|------|-------------------|---------|
| **部署速度** | ⭐⭐⭐ 快(一键启动) | ⭐⭐ 中等(需手动安装依赖) |
| **环境隔离** | ⭐⭐⭐ 完全隔离 | ⭐ 依赖系统 Python/Node 版本 |
| **可移植性** | ⭐⭐⭐ 任意 Linux 一致运行 | ⭐⭐ 依赖发行版 |
| **Playwright 兼容性** | ⭐⭐⭐ 容器内安装 Chromium | ⭐⭐ 需系统级依赖库 |
| **维护成本** | ⭐⭐⭐ 低(镜像升级) | ⭐⭐ 需手动维护 |
| **资源占用** | ⭐⭐ 略高(容器层) | ⭐⭐⭐ 原生性能 |
| **适合场景** | 生产环境、团队协作 | 开发测试、临时验证 |
---
## 2. 方案一:Docker 容器化部署(推荐)
### 2.1 整体架构
```
┌─────────────────────────────────────────────────┐
│ Linux 服务器 │
│ │
│ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ Nginx │ │ Docker Compose │ │
│ │ (反向代理) │──▶│ │ │
│ │ :80 / :443 │ │ ┌────────┐ ┌────────┐ │ │
│ │ SSL 终止 │ │ │ Backend│ │Frontend│ │ │
│ │ WebSocket │ │ │ :8001 │ │ :3000 │ │ │
│ │ 代理 │ │ └───┬────┘ └────────┘ │ │
│ └──────────────┘ │ │ │ │
│ │ ┌───▼────┐ │ │
│ │ │ SQLite │ │ │
│ │ │(volume)│ │ │
│ │ └────────┘ │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────┘
```
### 2.2 目录结构
```
platform-auto-test/
├── deploy/
│ ├── docker-compose.yml # 主编排文件
│ ├── Dockerfile.backend # 后端镜像构建
│ ├── Dockerfile.frontend # 前端镜像构建(Nginx 静态托管)
│ ├── nginx/
│ │ └── default.conf # Nginx 站点配置
│ └── .env # 环境变量文件
├── backend/
│ └── ... # 后端源码(不变)
├── frontend/
│ └── ... # 前端源码(不变)
└── data/ # 数据持久化(gitignored)
├── test_platform.db
├── screenshots/
└── reports/
```
### 2.3 后端 Dockerfile
```dockerfile
# deploy/Dockerfile.backend
FROM python:3.10-slim
WORKDIR /app
# 安装系统依赖(Playwright 需要)
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
gnupg \
libnss3 \
libnspr4 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libdbus-1-3 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libpango-1.0-0 \
libcairo2 \
libasound2 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 安装 Playwright Chromium(Linux 版本)
RUN playwright install chromium
# 复制后端代码
COPY backend/ .
# 创建数据目录
RUN mkdir -p /app/data/screenshots /app/data/reports
# 暴露端口
EXPOSE 8001
# 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
```
### 2.4 前端 Dockerfile(Nginx 静态托管)
```dockerfile
# deploy/Dockerfile.frontend
# ---- 构建阶段 ----
FROM node:20-alpine AS build
WORKDIR /app
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ .
RUN npm run build
# ---- 运行阶段 ----
FROM nginx:alpine
# 复制构建产物
COPY --from=build /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
### 2.5 Nginx 配置
```nginx
# deploy/nginx/default.conf
server {
listen 80;
server_name _;
# 前端静态文件
root /usr/share/nginx/html;
index index.html;
# 前端路由(SPA 支持)
location / {
try_files $uri $uri/ /index.html;
}
# API 反向代理到后端
location /api/ {
proxy_pass http://backend:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
# WebSocket 反向代理
location /api/executions/ws/ {
proxy_pass http://backend:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
# 文件服务
location /api/files/ {
proxy_pass http://backend:8001;
proxy_set_header Host $host;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}
```
### 2.6 Docker Compose 编排
```yaml
# deploy/docker-compose.yml
version: "3.8"
services:
backend:
build:
context: ..
dockerfile: deploy/Dockerfile.backend
container_name: plat-auto-test-backend
ports:
- "8001:8001"
volumes:
- ../data:/app/data
environment:
- DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
- PLAYWRIGHT_HEADLESS=true
- PLAYWRIGHT_TIMEOUT=30000
- LOG_LEVEL=INFO
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8001/health"]
interval: 30s
timeout: 10s
retries: 3
frontend:
build:
context: ..
dockerfile: deploy/Dockerfile.frontend
container_name: plat-auto-test-frontend
ports:
- "80:80"
depends_on:
backend:
condition: service_healthy
restart: unless-stopped
```
### 2.7 环境变量文件
```bash
# deploy/.env
# 数据库
DATABASE_URL=sqlite+aiosqlite:///./data/test_platform.db
# Playwright
PLAYWRIGHT_HEADLESS=true
PLAYWRIGHT_TIMEOUT=30000
# 日志
LOG_LEVEL=INFO
# 安全(生产环境建议修改)
SECRET_KEY=change-this-to-a-random-string
```
### 2.8 一键部署脚本
```bash
# deploy/deploy.sh
#!/bin/bash
set -e
echo "=== 平台自动化测试系统 - Docker 部署脚本 ==="
# 检查 Docker 是否安装
if ! command -v docker &> /dev/null; then
echo "错误: Docker 未安装"
echo "请先安装 Docker: https://docs.docker.com/engine/install/"
exit 1
fi
# 检查 Docker Compose 是否安装
if ! command -v docker-compose &> /dev/null; then
echo "错误: Docker Compose 未安装"
echo "请先安装 Docker Compose: https://docs.docker.com/compose/install/"
exit 1
fi
# 创建数据目录
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
mkdir -p "$PROJECT_DIR/data/screenshots" "$PROJECT_DIR/data/reports"
echo "📦 构建并启动服务..."
cd "$SCRIPT_DIR"
docker-compose up -d --build
echo "⏳ 等待服务就绪..."
sleep 10
# 健康检查
echo "🔍 检查后端健康状态..."
curl -s http://localhost:8001/health || echo "⚠️ 后端未响应,请检查日志"
echo ""
echo "✅ 部署完成!"
echo " 前端: http://$(hostname -I | awk '{print $1}')"
echo " API: http://$(hostname -I | awk '{print $1}')/api"
echo " Docs: http://$(hostname -I | awk '{print $1}')/docs"
echo ""
echo "📋 查看日志: docker-compose logs -f"
echo "🛑 停止服务: docker-compose down"
```
---
## 3. 方案二:裸机部署(传统方式)
### 3.1 基础环境准备
```bash
# ===== Ubuntu/Debian =====
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3.10 python3.10-venv python3-pip \
nodejs npm nginx curl
# ===== CentOS/RHEL =====
sudo yum install -y epel-release
sudo yum install -y python3.10 python3-pip nodejs nginx curl
```
### 3.2 安装 Playwright 系统依赖
```bash
# Playwright 在 Linux 上需要系统级库
# Ubuntu/Debian
sudo apt install -y \
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libdbus-1-3 libxkbcommon0 \
libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
libgbm1 libpango-1.0-0 libcairo2 libasound2
# CentOS/RHEL
sudo yum install -y \
nss nspr atk at-spi2-atk cups-libs libdrm \
dbus-libs libxkbcommon libXcomposite libXdamage \
libXfixes libXrandr mesa-libgbm pango cairo alsa-lib
```
### 3.3 后端部署
```bash
# 1. 克隆代码
git clone http://git.ubainsyun.com/bing/ubains-module-test.git
cd ubains-module-test
git checkout platform-auto-test
# 2. 创建 Python 虚拟环境
python3 -m venv venv
source venv/bin/activate
# 3. 安装依赖
cd backend
pip install -r requirements.txt
# 4. 安装 Playwright Chromium
playwright install chromium
# 5. 创建数据目录
mkdir -p data/screenshots data/reports
# 6. 配置 systemd 服务(见下方)
```
### 3.4 systemd 服务配置
```ini
# /etc/systemd/system/plat-auto-test-backend.service
[Unit]
Description=平台自动化测试系统 - 后端服务
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/ubains-module-test/backend
Environment="PATH=/opt/ubains-module-test/venv/bin"
Environment="PLAYWRIGHT_HEADLESS=true"
Environment="LOG_LEVEL=INFO"
ExecStart=/opt/ubains-module-test/venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8001 --workers 2
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
```
### 3.5 前端部署
```bash
# 1. 安装依赖并构建
cd frontend
npm ci
npm run build
# 2. 构建产物在 frontend/dist/ 目录
# 配置 Nginx 指向该目录(见下方)
```
### 3.6 Nginx 配置(裸机版)
```nginx
# /etc/nginx/sites-available/plat-auto-test
server {
listen 80;
server_name _;
# 前端静态文件
root /opt/ubains-module-test/frontend/dist;
index index.html;
# SPA 路由
location / {
try_files $uri $uri/ /index.html;
}
# API 反向代理
location /api/ {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
# WebSocket 代理
location /api/executions/ws/ {
proxy_pass http://127.0.0.1:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
# 文件服务
location /api/files/ {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
# 日志
access_log /var/log/nginx/plat-auto-test-access.log;
error_log /var/log/nginx/plat-auto-test-error.log;
}
```
```bash
# 启用站点
sudo ln -sf /etc/nginx/sites-available/plat-auto-test /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
---
## 4. 部署前改造清单
### 4.1 后端代码改造(Windows → Linux 兼容)
| 文件 | 改造内容 | 说明 |
|------|---------|------|
| `main.py` | 条件判断 `sys.platform == 'win32'` 不用改 | 已写好,Linux 自动跳过 ProactorEventLoop |
| `config.py` | 无需修改 | 环境变量配置已支持 |
| `database.py` | 无需修改 | SQLAlchemy 跨平台兼容 |
| `playwright_executor.py` | 无需修改 | 同步 API 在 Linux 上同样工作 |
**注意**`config.py``DATABASE_URL` 默认使用相对路径 `./data/`,生产环境建议通过环境变量覆盖为绝对路径,如:
```bash
export DATABASE_URL="sqlite+aiosqlite:////opt/data/test_platform.db"
```
### 4.2 安全性加固
```python
# config.py 中的 CORS 配置
# 生产环境应改为明确的域名,而非 "*"
CORS_ORIGINS: list = os.getenv(
"CORS_ORIGINS",
"http://your-domain.com"
).split(",")
```
### 4.3 数据库迁移策略
**当前**:SQLite 文件数据库
**生产建议**:考虑迁移到 PostgreSQL(如需高并发)
```bash
# 数据备份(迁移前)
cp data/test_platform.db data/test_platform.db.bak.$(date +%Y%m%d)
```
### 4.4 日志持久化
```yaml
# docker-compose 补充
services:
backend:
volumes:
- ../data:/app/data
- ../logs:/app/logs # 日志持久化
```
---
## 5. CI/CD 集成
### 5.1 GitHub Actions 示例
```yaml
# .github/workflows/deploy.yml
name: Deploy to Linux Server
on:
push:
branches: [platform-auto-test]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker images
run: |
docker build -t plat-auto-test-backend -f deploy/Dockerfile.backend .
docker build -t plat-auto-test-frontend -f deploy/Dockerfile.frontend .
- name: Push to registry (可选)
run: |
docker tag plat-auto-test-backend ${{ secrets.REGISTRY }}/plat-auto-test-backend:latest
docker push ${{ secrets.REGISTRY }}/plat-auto-test-backend:latest
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /opt/ubains-module-test
git pull
cd deploy
docker-compose pull
docker-compose up -d --build
```
### 5.2 手动部署命令
```bash
# 推送代码到远程
git push origin platform-auto-test
# SSH 到服务器,拉取并部署
ssh user@your-server
cd /opt/ubains-module-test
git pull origin platform-auto-test
cd deploy
docker-compose up -d --build
```
---
## 6. 运维与监控
### 6.1 常用运维命令
```bash
# Docker 部署
docker-compose logs -f # 查看实时日志
docker-compose logs backend # 查看后端日志
docker-compose logs frontend # 查看前端日志
docker-compose down # 停止服务
docker-compose up -d # 启动服务
docker-compose restart backend # 重启后端
docker-compose restart frontend # 重启前端
# 数据备份
docker exec plat-auto-test-backend sh -c "cp /app/data/test_platform.db /app/data/backup_$(date +%Y%m%d).db"
# 进入容器
docker exec -it plat-auto-test-backend /bin/bash
```
### 6.2 健康检查
```bash
# 检查所有服务
curl http://localhost:8001/health
# 预期响应:
# {"status":"healthy","service":"平台自动化测试系统","version":"1.0.0","debug":false}
# 检查 Docker 容器状态
docker-compose ps
# 检查系统资源
docker stats
```
### 6.3 监控告警建议
| 指标 | 告警阈值 | 说明 |
|------|---------|------|
| CPU 使用率 | > 80% | Playwright 执行时 CPU 可能飙升 |
| 内存使用率 | > 80% | 每个浏览器实例约 200-500MB |
| 磁盘空间 | < 20% | 截图和报告会占用空间 |
| 服务宕机 | 任何不可用 | 自动重启 |
### 6.4 定期任务
```bash
# 数据清理脚本(建议 crontab 每周执行)
# 清理 30 天前的截图和报告
find /opt/ubains-module-test/data/screenshots -type f -mtime +30 -delete
find /opt/ubains-module-test/data/reports -type f -mtime +30 -delete
# 数据库备份(每天凌晨 3 点)
0 3 * * * cp /opt/ubains-module-test/data/test_platform.db /opt/backups/db_$(date +\%Y\%m\%d).db
```
---
## 7. 常见问题
### 7.1 Playwright 在 Linux 容器中运行失败
**现象**`BrowserType.launch` 报错 `Missing libraries`
**原因**:容器缺少 Chromium 系统依赖
**解决**:Dockerfile 中已包含所有依赖库,确保 `apt-get install` 步骤完整
### 7.2 WebSocket 连接失败
**现象**:前端执行页面 WebSocket 无法连接
**原因**:Nginx 未配置 WebSocket 升级头
**解决**:确保 Nginx 配置包含:
```nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```
### 7.3 SQLite 数据库锁定
**现象**`database is locked` 错误
**原因**:多 worker 并发写入 SQLite
**解决**
- 方案 1:`uvicorn` 启动时只使用 `--workers 1`(SQLite 不推荐多 worker)
- 方案 2:迁移到 PostgreSQL(推荐生产环境)
### 7.4 前端 API 请求 404
**现象**:前端请求 `/api/api/cases` 双重前缀
**原因**:Nginx 代理路径与前端 baseURL 叠加
**解决**:前端 `baseURL` 保持空字符串,Nginx 中 `location /api/` 直接代理到后端
### 7.5 截图目录权限
**现象**:执行时截图保存失败
**解决**
```bash
# 确保 data 目录可写
chown -R 1000:1000 /opt/ubains-module-test/data
# 或直接开放权限
chmod -R 777 /opt/ubains-module-test/data
```
---
## 8. 附录:脚本模板
### 8.1 快速部署脚本(Docker 版)
```bash
# quick-deploy.sh
# 用法: curl -sSL https://your-server/quick-deploy.sh | bash
set -e
REPO_URL="http://git.ubainsyun.com/bing/ubains-module-test.git"
BRANCH="platform-auto-test"
INSTALL_DIR="/opt/ubains-module-test"
echo "🔄 克隆代码..."
git clone -b $BRANCH $REPO_URL $INSTALL_DIR
echo "📦 构建并启动..."
cd $INSTALL_DIR/deploy
docker-compose up -d --build
echo ""
echo "✅ 部署完成!"
echo "访问地址: http://$(curl -s ifconfig.me)"
```
### 8.2 数据库迁移到 PostgreSQL(可选)
```python
# backend/app/config.py
# 生产环境使用 PostgreSQL 只需设置环境变量:
# export DATABASE_URL="postgresql+asyncpg://user:password@localhost:5432/plat_auto_test"
# 需要在 requirements.txt 中增加:
# asyncpg==0.29.0
# psycopg2-binary==2.9.9
```
### 8.3 HTTPS 配置(Let's Encrypt)
```bash
# 安装 certbot
sudo apt install -y certbot python3-certbot-nginx
# 获取证书
sudo certbot --nginx -d your-domain.com
# 自动续期(certbot 默认自动添加 systemd timer)
sudo certbot renew --dry-run
```
---
## 部署路线图
| 阶段 | 内容 | 预计时间 |
|------|------|---------|
| **Phase 1** | 代码改造 + 提交 Dockerfile/Compose/Nginx 配置 | 1 天 |
| **Phase 2** | 服务器环境准备(Docker 安装、网络配置) | 0.5 天 |
| **Phase 3** | 部署测试 + 功能验证(执行用例验证) | 1 天 |
| **Phase 4** | HTTPS 配置 + 域名绑定 | 0.5 天 |
| **Phase 5** | CI/CD 接入 + 监控告警 | 1 天 |
| **Phase 6** | (可选)迁移 PostgreSQL | 2 天 |
---
*本文档由 Claude Code 生成,建议根据实际服务器环境(操作系统、网络策略、资源限制)调整参数。*
\ No newline at end of file
...@@ -1240,7 +1240,6 @@ ...@@ -1240,7 +1240,6 @@
"resolved": "https://mirrors.cloud.tencent.com/npm/@types/lodash-es/-/lodash-es-4.17.12.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/lodash": "*" "@types/lodash": "*"
} }
...@@ -2007,15 +2006,13 @@ ...@@ -2007,15 +2006,13 @@
"version": "4.18.1", "version": "4.18.1",
"resolved": "https://mirrors.cloud.tencent.com/npm/lodash/-/lodash-4.18.1.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash-es": { "node_modules/lodash-es": {
"version": "4.18.1", "version": "4.18.1",
"resolved": "https://mirrors.cloud.tencent.com/npm/lodash-es/-/lodash-es-4.18.1.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/lodash-es/-/lodash-es-4.18.1.tgz",
"integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash-unified": { "node_modules/lodash-unified": {
"version": "1.0.3", "version": "1.0.3",
...@@ -2287,7 +2284,6 @@ ...@@ -2287,7 +2284,6 @@
"integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"chokidar": "^5.0.0", "chokidar": "^5.0.0",
"immutable": "^5.1.5", "immutable": "^5.1.5",
...@@ -2338,7 +2334,6 @@ ...@@ -2338,7 +2334,6 @@
"integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"peer": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0", "acorn": "^8.15.0",
...@@ -2363,7 +2358,6 @@ ...@@ -2363,7 +2358,6 @@
"resolved": "https://mirrors.cloud.tencent.com/npm/typescript/-/typescript-5.9.3.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true, "devOptional": true,
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
...@@ -2377,7 +2371,6 @@ ...@@ -2377,7 +2371,6 @@
"resolved": "https://mirrors.cloud.tencent.com/npm/vite/-/vite-5.4.21.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.43", "postcss": "^8.4.43",
...@@ -2443,7 +2436,6 @@ ...@@ -2443,7 +2436,6 @@
"version": "3.5.39", "version": "3.5.39",
"resolved": "https://mirrors.cloud.tencent.com/npm/vue/-/vue-3.5.39.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/vue/-/vue-3.5.39.tgz",
"integrity": "sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==", "integrity": "sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==",
"peer": true,
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.39", "@vue/compiler-dom": "3.5.39",
"@vue/compiler-sfc": "3.5.39", "@vue/compiler-sfc": "3.5.39",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论