添加Docker自包含部署分支

- 新增 Seg_Server_Docker 自包含部署内容,包含前后端、FastAPI、Celery、PostgreSQL、Redis、MinIO、演示视频和 DICOM 数据。

- 保留 demo 数据以支持恢复演示出厂设置,排除 SAM 2.1 .pt 权重并在 README 中补充下载命令。

- 补充 GPU 部署、backend/worker 镜像复用、frpc/frps + NPM 公网域名反代部署说明。

- 在 .env/.env.example 中用 # XXXX 标注局域网和公网域名部署需要修改的配置项。

- 添加部署分支 .gitignore,忽略本地模型权重、构建产物、缓存和日志。
This commit is contained in:
2026-05-07 19:06:07 +08:00
commit b5413066a0
396 changed files with 32742 additions and 0 deletions

504
README.md Normal file
View File

@@ -0,0 +1,504 @@
# Seg_Server_Docker 部署说明
`Seg_Server_Docker` 是语义分割系统的自包含 Docker 部署包。目标不是“最小可运行”,而是尽量完整、可搬迁、能适应 CPU/GPU 与局域网访问等常见环境的可运行版本。
部署时只需要保留并移动这一整个文件夹。默认配置只引用本目录内的 `models/``demo/`、前端源码、后端源码和 Docker 配置,不依赖旁边的源码仓库,也不依赖固定宿主机路径。
## 目录内容
```text
Seg_Server_Docker/
├── docker-compose.yml # 基础服务前端、后端、worker、PostgreSQL、Redis、MinIO
├── docker-compose.gpu.yml # GPU 覆盖配置:给 backend/worker 透传 NVIDIA GPU
├── Dockerfile.backend # FastAPI + Celery + PyTorch + SAM2 后端镜像
├── Dockerfile.frontend # React 前端构建 + Nginx 静态服务
├── .env # 当前部署环境变量
├── .env.example # 环境变量模板
├── backend/ # FastAPI 后端代码
├── src/ # React 前端代码
├── public/ # 前端静态资源
├── docker/ # Nginx 配置等 Docker 辅助文件
├── demo/ # 演示数据
│ ├── 演视LC视频序列.mp4
│ └── 演视DICOM序列/
└── models/ # SAM 2.1 权重,容器内挂载为 /app/models
```
## 服务说明
| 服务 | 容器名 | 作用 | 默认端口 |
|---|---|---|---|
| frontend | `seg-frontend` | Web 前端页面 | `3000 -> 80` |
| backend | `seg-backend` | FastAPI API、登录、项目、模板、标注、单帧 AI 分割 | `8000 -> 8000` |
| worker | `seg-worker` | Celery 后台任务、视频拆帧、DICOM 解析、AI 自动推理/传播 | 内部访问 |
| postgres | `seg-postgres` | 元数据数据库 | 内部访问 |
| redis | `seg-redis` | Celery broker/result backend | 内部访问 |
| minio | `seg-minio` | 视频、DICOM、帧图、缩略图等对象存储 | `9000``9001` |
`backend` 构建并发布 `seg-server-backend:latest` 镜像,`worker` 直接复用这个镜像。更新后端依赖、PyTorch、SAM2 或系统包时,只需要重建 `backend` 镜像,再同时重启 `backend``worker`,避免 API 端显示模型可用但 worker 执行传播时缺依赖。
`worker` 配置了 `pull_policy: never`,只使用本地 `seg-server-backend:latest`,不会尝试从远端镜像仓库拉取这个内部镜像。首次部署请使用带 `--build` 的启动命令,让 `backend` 先构建出本地镜像。
## 部署前准备
1. 安装 Docker Engine 和 Docker Compose plugin。
2. 确认当前目录包含演示数据:
```bash
ls demo/演视LC视频序列.mp4
ls demo/演视DICOM序列
```
3. 确认当前目录包含 SAM 2.1 权重:
```bash
ls -lh models/
```
推荐至少包含:
```text
models/sam2_hiera_tiny.pt
models/sam2.1_hiera_small.pt
models/sam2.1_hiera_base_plus.pt
models/sam2.1_hiera_large.pt
```
如果只部署部分权重,系统仍可启动;缺失权重对应的模型变体会显示不可用。
### 下载 SAM 2.1 权重
部署分支不提交 `.pt` 权重文件。首次部署前在本目录执行:
```bash
mkdir -p models
wget -O models/sam2_hiera_tiny.pt https://dl.fbaipublicfiles.com/segment_anything_2/072824/sam2_hiera_tiny.pt
wget -O models/sam2.1_hiera_small.pt https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_small.pt
wget -O models/sam2.1_hiera_base_plus.pt https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt
wget -O models/sam2.1_hiera_large.pt https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt
```
也可以只下载 tiny/small 等需要的权重。`sam2_hiera_tiny.pt` 是兼容旧名,系统会把它作为 `sam2.1_hiera_tiny` 的 fallback 使用。
## 环境变量
部署前编辑 `.env`
```ini
PUBLIC_HOST=localhost
VITE_API_BASE_URL=
VITE_WS_PROGRESS_URL=
FRONTEND_PORT=3000
BACKEND_PORT=8000
MINIO_PORT=9000
MINIO_CONSOLE_PORT=9001
POSTGRES_USER=seguser
POSTGRES_PASSWORD=segpass123
POSTGRES_DB=segserver
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_PUBLIC_ENDPOINT=localhost:9000
MINIO_SECURE=false
SAM_MODELS_DIR=./models
CORS_ORIGINS=["http://localhost:3000","http://127.0.0.1:3000"]
JWT_SECRET_KEY=change-this-to-a-long-random-production-secret
ACCESS_TOKEN_EXPIRE_MINUTES=1440
DEFAULT_ADMIN_USERNAME=admin
DEFAULT_ADMIN_PASSWORD=123456
```
局域网访问时,把 `PUBLIC_HOST` 改成部署机器 IP并把对应前端地址加入 `CORS_ORIGINS`。例如前端通过 `http://192.168.3.11:3000` 打开时:
```ini
PUBLIC_HOST=192.168.3.11
VITE_API_BASE_URL=
VITE_WS_PROGRESS_URL=
MINIO_PUBLIC_ENDPOINT=192.168.3.11:9000
MINIO_SECURE=false
CORS_ORIGINS=["http://192.168.3.11:3000","http://localhost:3000","http://127.0.0.1:3000"]
```
保持 `SAM_MODELS_DIR=./models` 可以让部署包自包含、可搬迁。只有在刻意共享外部模型缓存时,才把它改成其他路径。
`.env``.env.example` 中用 `# XXXX` 标出的配置项,是局域网部署或公网域名反代部署时最常需要修改的地方。
生产或长期演示环境请修改:
- `JWT_SECRET_KEY`
- `DEFAULT_ADMIN_PASSWORD`
- `POSTGRES_PASSWORD`
- `MINIO_ACCESS_KEY`
- `MINIO_SECRET_KEY`
## CPU 启动
适用于没有 NVIDIA GPU 或暂时不配置 GPU 透传的环境:
```bash
docker compose up -d --build
```
查看状态:
```bash
docker compose ps
curl http://localhost:8000/health
```
CPU 模式下,如果 PyTorch、SAM2 和 `.pt` 权重存在,模型可以加载,但推理速度明显慢于 GPU。
## GPU 启动
GPU 模式要求宿主机满足:
1. NVIDIA 驱动可用。
2. `nvidia-smi` 能看到 GPU。
3. Docker 已安装并配置 NVIDIA Container Toolkit。
4. `docker run --rm --gpus all ... nvidia-smi` 能在容器内看到 GPU。
先验证宿主机 GPU
```bash
nvidia-smi
```
验证 Docker GPU 透传:
```bash
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
```
如果 Docker GPU 验证失败,需要先安装并配置 NVIDIA Container Toolkit
```bash
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
启动 GPU 版:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d --build
```
验证 backend 和 worker 都能看到 GPU
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml exec -T backend python - <<'PY'
import torch
print(torch.cuda.is_available())
print(torch.cuda.device_count())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "NO CUDA")
PY
docker compose -f docker-compose.yml -f docker-compose.gpu.yml exec -T worker python - <<'PY'
import torch
print(torch.cuda.is_available())
print(torch.cuda.device_count())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "NO CUDA")
PY
```
如果 backend 是 GPU 但 worker 不是 GPUAI 自动推理/传播会失败。此时重建并重启二者:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml build backend
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d backend worker
```
## 公网域名 + frpc/frps + NPM
如果公网服务器绑定了域名,并通过 frpc/frps 把内网部署机器端口映射到公网服务器本机端口,再由 Nginx Proxy Manager 反向代理,推荐使用三个子域名:
```text
seg.example.com -> 前端
seg-api.example.com -> 后端 API + WebSocket
seg-minio.example.com -> MinIO 图片/帧图/缩略图
```
推荐链路:
```text
浏览器
-> 公网服务器 NPM
-> 公网服务器本机 frps 映射端口
-> frpc
-> 内网部署机器的 3000 / 8000 / 9000
```
端口映射建议:
```text
内网部署机器 3000 -> 公网服务器本机 13000 -> NPM: seg.example.com
内网部署机器 8000 -> 公网服务器本机 18000 -> NPM: seg-api.example.com
内网部署机器 9000 -> 公网服务器本机 19000 -> NPM: seg-minio.example.com
```
NPM 中配置三个 Proxy Host
```text
seg.example.com
Scheme: http
Forward Hostname / IP: 127.0.0.1
Forward Port: 13000
seg-api.example.com
Scheme: http
Forward Hostname / IP: 127.0.0.1
Forward Port: 18000
Websocket Support: 开启
seg-minio.example.com
Scheme: http
Forward Hostname / IP: 127.0.0.1
Forward Port: 19000
```
建议三个域名都在 NPM 里申请 HTTPS 证书,并开启 HTTPS。公网 HTTPS 场景下,内网 `Seg_Server_Docker/.env` 需要修改 `# XXXX` 标出的几项:
```ini
# XXXX Public-domain access through frpc/frps + NPM
PUBLIC_HOST=seg.example.com
# XXXX Frontend build-time API/WebSocket endpoints
VITE_API_BASE_URL=https://seg-api.example.com
VITE_WS_PROGRESS_URL=wss://seg-api.example.com/ws/progress
# XXXX Browser-facing MinIO endpoint
MINIO_PUBLIC_ENDPOINT=seg-minio.example.com
MINIO_SECURE=true
# XXXX Browser origins
CORS_ORIGINS=["https://seg.example.com"]
```
修改 `VITE_API_BASE_URL``VITE_WS_PROGRESS_URL` 后必须重建前端,因为它们是前端构建期变量:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml build frontend
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d frontend backend worker
```
如果同时从零启动 GPU 版:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d --build
```
公网域名部署后,浏览器只需要访问:
```text
https://seg.example.com
```
不要只反代前端 `3000`。后端 `8000` 不通会导致登录、项目、任务和 AI 接口失败MinIO `9000` 不通会导致帧图、缩略图、预览图等资源加载失败。
## 访问入口
默认地址:
```text
前端http://localhost:3000
后端http://localhost:8000
MinIO APIhttp://localhost:9000
MinIO 控制台http://localhost:9001
```
局域网访问时,把 `localhost` 换成 `.env` 中的 `PUBLIC_HOST`
默认账号:
```text
用户名admin
密码123456
```
## 演示数据和恢复出厂设置
演示数据固定从部署包本地读取:
```text
demo/演视LC视频序列.mp4
demo/演视DICOM序列/
```
系统启动和“恢复演示出厂设置”都会使用这两个路径。恢复后应出现:
- `演视LC视频序列`
- `演视DICOM序列`
DICOM 序列会按文件名自然顺序读取,避免切片顺序错位。
## 常用运维命令
启动:
```bash
docker compose up -d
```
GPU 启动:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
```
停止:
```bash
docker compose down
```
查看容器:
```bash
docker compose ps
```
查看日志:
```bash
docker compose logs -f backend
docker compose logs -f worker
docker compose logs -f frontend
```
重建前后端:
```bash
docker compose build backend frontend
docker compose up -d backend worker frontend
```
重建 GPU 版后端和 worker
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml build backend
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d backend worker
```
清空当前部署数据:
```bash
docker compose down -v
docker compose up -d --build
```
注意:`down -v` 会删除数据库和 MinIO 对象存储卷,项目、帧、标注和上传文件都会清空。
## 模型状态验证
登录后前端左下角会显示 CPU/GPU 状态。也可以通过后端接口检查:
```bash
curl http://localhost:8000/health
```
模型状态接口需要登录 token。更简单的容器内检查方式
```bash
docker compose exec -T backend python - <<'PY'
from services.sam_registry import sam_registry
print(sam_registry.runtime_status())
PY
```
GPU 版:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml exec -T backend python - <<'PY'
from services.sam_registry import sam_registry
print(sam_registry.runtime_status())
PY
```
## 常见问题
### 前端能打开,但图片或缩略图打不开
检查 `.env`
- `PUBLIC_HOST` 是否是浏览器可以访问到的主机名或 IP。
- `MINIO_PORT` 是否开放。
- `CORS_ORIGINS` 是否包含当前前端地址。
修改 `.env` 后重启:
```bash
docker compose up -d backend worker frontend
```
### 左下角显示 CPU
先确认是 CPU 部署还是 GPU 部署。GPU 部署必须使用:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
```
再检查 Docker GPU 透传:
```bash
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
```
如果这条命令失败,问题在宿主机 Docker GPU runtime不在应用代码。
### 单帧 AI 分割可用,但 AI 自动推理无结果
检查 `seg-worker` 是否和 `seg-backend` 使用同一个镜像,并且 worker 是否能看到 PyTorch、SAM2 和 GPU
```bash
docker inspect seg-backend seg-worker --format '{{.Name}} {{.Image}} {{.Config.Image}}'
docker compose -f docker-compose.yml -f docker-compose.gpu.yml exec -T worker python - <<'PY'
import importlib.util, torch
print("torch", bool(importlib.util.find_spec("torch")))
print("sam2", bool(importlib.util.find_spec("sam2")))
print("cuda", torch.cuda.is_available())
PY
```
如果 worker 缺依赖,重建并重启:
```bash
docker compose -f docker-compose.yml -f docker-compose.gpu.yml build backend
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d backend worker
```
### 恢复演示出厂设置后项目为空
检查 demo 文件是否仍在部署包本地:
```bash
ls demo/演视LC视频序列.mp4
ls demo/演视DICOM序列
```
如果目录被移动或删掉,恢复出厂设置无法重新生成演示项目。
### 模型不可用
检查 `models/`
```bash
ls -lh models/
```
缺失的 `.pt` 权重对应模型会显示不可用。部署包默认从 `./models` 挂载到容器内 `/app/models`