Files
operating-room-monitor-server/docs/离线镜像tarball部署.md
Kevin 1af442481e 重组为 backend/clients/docs 三层结构,并清理 git 污染。
将后端迁入 backend/,完善根目录 .gitignore,删除误提交的 .mypy_cache 缓存文件。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 16:02:25 +08:00

274 lines
11 KiB
Markdown
Executable File
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.
# 离线镜像tarball部署说明
本文说明 **方式 B**:厂商在可联网环境构建并导出 API 镜像为 `tar`/`tar.gz`,客户在目标服务器 **不拉取 API 镜像构建上下文** 的情况下,通过 `docker load` 加载后启动完整后端PostgreSQL + MinIO + API
> 说明:仓库默认的 `backend/docker-compose.yml` 中 `api` 使用 `build:`。客户侧使用 tarball 时,必须使用下方 **「仅使用已加载镜像」** 的 Compose 片段(将 `build` 换成 `image`),否则仍会尝试本地构建。
---
## 一、厂商侧:构建与导出
在已具备完整源码与 Docker 的环境中(与生产交付相同架构,一般为 **linux/amd64**
### 1. 构建并打标签
```bash
cd /path/to/operation-room-monitor/backend
docker compose build api
docker tag operation-room-monitor-server-api:latest <交付镜像名>:<版本号>
# 示例docker tag operation-room-monitor-server-api:latest acme/or-monitor-api:1.0.0
```
若在 Apple Silicon 等设备上打包给 x86 服务器,需启用跨平台构建(示例):
```bash
docker buildx build --platform linux/amd64 -t <交付镜像名>:<版本号> --load .
```
### 2. 导出为 tarball
单机文件交付常用压缩包:
```bash
docker save <交付镜像名>:<版本号> | gzip -9 > or-monitor-api_<版本号>_linux-amd64.tar.gz
```
导出多个镜像(可选,用于 **完全离线** 且客户机不能拉 Postgres/MinIO 时):
```bash
docker pull m.daocloud.io/docker.io/library/postgres:16-alpine
docker pull m.daocloud.io/docker.io/minio/minio:latest
docker save \
<交付镜像名>:<版本号> \
m.daocloud.io/docker.io/library/postgres:16-alpine \
m.daocloud.io/docker.io/minio/minio:latest \
| gzip -9 > or-monitor-stack_<版本号>_offline.tar.gz
```
### 3. 建议一并交付的文件
| 文件 | 说明 |
|------|------|
| `or-monitor-api_*.tar.gz`(或全栈 `*_offline.tar.gz` | 镜像包 |
| 本文档 | 客户部署步骤 |
| `docker-compose.yml` **或** 下文「离线 Compose」全文 | `api` 使用 `image:` 而非 `build:`(位于 `backend/` |
| `backend/.env.example`(按项目实际改名) | 环境变量模板,勿包含真实密钥 plaintext 于公共渠道 |
|(可选)语音确认前端静态包、`OR_SITE_CONFIG` 样例 | 按需 |
---
## 二、客户侧:环境要求
- **Docker** 与 **Docker Compose**Compose V2`docker compose`)。
- **CPU 架构**:与 tarball 构建时声明一致(常见 **amd64**)。
- **磁盘**PostgreSQL / MinIO 使用命名卷持久化;外加镜像解压空间,建议预留数十 GB。
- **端口**(默认值,可在 `.env` 中修改):
- `38080`HTTP API`API_PORT`
- `9000` / `9001`MinIO API / 控制台
- `5432`:仅在容器网络内使用,默认 **不映射到宿主机**
- **GPU必需**:镜像内含 CUDA 版 PyTorch客户机需安装 NVIDIA 驱动与 **NVIDIA Container Toolkit**,并保证 `nvidia-smi``docker run --gpus all` 正常。Compose 模板中 `api` 服务默认启用 `gpus: all`
---
## 三、客户侧:加载镜像
将 tarball 拷贝到服务器后:
```bash
gzip -dc or-monitor-api_<版本号>_linux-amd64.tar.gz | docker load
# 或docker load -i or-monitor-api_<版本号>_linux-amd64.tar
```
确认镜像已存在:
```bash
docker images | grep <交付镜像名>
```
若为「全栈离线包」,同样对整体 `tar.gz` 执行一次 `docker load` 即可导入多个镜像。
---
## 四、客户侧Compose 配置(使用已加载镜像)
在部署目录放置 `docker-compose.yml`**将 `api` 服务改为使用预加载镜像**,不要保留 `build:`。可直接使用下面模板(把镜像名与版本改成实际交付值):
```yaml
# 与仓库主 compose 行为一致,但 api 使用已 load 的镜像(无 build
services:
db:
image: m.daocloud.io/docker.io/library/postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-operation_room}
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""]
interval: 5s
timeout: 5s
retries: 20
start_period: 5s
minio:
image: m.daocloud.io/docker.io/minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin}
ports:
- "${MINIO_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
volumes:
- minio_data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
api:
image: <交付镜像名>:<版本号>
gpus: all
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-operation_room}
POSTGRES_HOST: db
POSTGRES_PORT: 5432
CONSUMABLE_CLASSIFIER_IMGSZ: ${CONSUMABLE_CLASSIFIER_IMGSZ:-224}
CONSUMABLE_CLASSIFIER_DEVICE: ${CONSUMABLE_CLASSIFIER_DEVICE:-}
CONSUMABLE_CLASSIFIER_TOPK: ${CONSUMABLE_CLASSIFIER_TOPK:-5}
CONSUMABLE_MIN_CLS_CONFIDENCE: ${CONSUMABLE_MIN_CLS_CONFIDENCE:-0.5}
CONSUMABLE_VISION_WINDOW_SEC: ${CONSUMABLE_VISION_WINDOW_SEC:-15}
HAND_DETECTION_WEIGHTS: ${HAND_DETECTION_WEIGHTS:-}
HAND_DETECTION_IMGSZ: ${HAND_DETECTION_IMGSZ:-640}
HAND_DETECTION_DEVICE: ${HAND_DETECTION_DEVICE:-}
VIDEO_DEFAULT_BACKEND: ${VIDEO_DEFAULT_BACKEND:-rtsp}
VIDEO_RTSP_URL_TEMPLATE: ${VIDEO_RTSP_URL_TEMPLATE:-}
OR_SITE_CONFIG_JSON_FILE: ${OR_SITE_CONFIG_JSON_FILE:-}
VIDEO_CAMERA_BACKEND_OVERRIDES_JSON: ${VIDEO_CAMERA_BACKEND_OVERRIDES_JSON:-}
HIKVISION_SDK_ENABLED: ${HIKVISION_SDK_ENABLED:-false}
HIKVISION_LIB_DIR: ${HIKVISION_LIB_DIR:-/opt/hikvision/lib}
HIKVISION_DEVICE_IP: ${HIKVISION_DEVICE_IP:-}
HIKVISION_USER: ${HIKVISION_USER:-}
HIKVISION_PASSWORD: ${HIKVISION_PASSWORD:-}
HIKVISION_PREVIEW_RTSP_TEMPLATE: ${HIKVISION_PREVIEW_RTSP_TEMPLATE:-}
OPENCV_FFMPEG_CAPTURE_OPTIONS: ${OPENCV_FFMPEG_CAPTURE_OPTIONS:-rtsp_transport;tcp}
BAIDU_APP_ID: ${BAIDU_APP_ID:-}
BAIDU_API_KEY: ${BAIDU_API_KEY:-}
BAIDU_SECRET_KEY: ${BAIDU_SECRET_KEY:-}
BAIDU_ASR_DEV_PID: ${BAIDU_ASR_DEV_PID:-1537}
MINIO_ENDPOINT: ${DOCKER_MINIO_ENDPOINT:-minio:9000}
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
MINIO_BUCKET: ${MINIO_BUCKET:-operation-room-voice}
MINIO_SECURE: ${MINIO_SECURE:-false}
MINIO_REGION: ${MINIO_REGION:-}
DEMO_CORS_ENABLED: ${DEMO_CORS_ENABLED:-true}
DEMO_CORS_ORIGINS: ${DEMO_CORS_ORIGINS:-*}
DEMO_ORCHESTRATOR_ENABLED: ${DEMO_ORCHESTRATOR_ENABLED:-false}
DEMO_ORCHESTRATOR_RTSP_PORT: ${DEMO_ORCHESTRATOR_RTSP_PORT:-18554}
DEMO_ORCHESTRATOR_RTSP_JSON_HOST: ${DOCKER_DEMO_ORCHESTRATOR_RTSP_JSON_HOST:-host.docker.internal}
MEDIAMTX_DOCKER_IMAGE: ${MEDIAMTX_DOCKER_IMAGE:-m.daocloud.io/docker.io/bluenviron/mediamtx:latest}
command: >
sh -c "alembic upgrade head &&
uvicorn main:app --host 0.0.0.0 --port 8000"
ports:
- "${API_PORT:-38080}:8000"
depends_on:
db:
condition: service_healthy
minio:
condition: service_started
restart: unless-stopped
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)",
]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
volumes:
pgdata:
minio_data:
```
**离线且未交付 Postgres/MinIO 镜像时**:需客户机对上述 `db``minio``image:` 仍能拉取(或改用厂商提供的全栈 `docker save` 包,`image` 名需与导出时完全一致)。
---
## 五、环境变量与密钥
在同一目录(`backend/`)放置 `.env`(可参考 `backend/.env.example`)。至少建议关注:
- `POSTGRES_PASSWORD`:生产请务必改为强密码。
- `API_PORT`:宿主机监听端口。
- 语音链路:`BAIDU_*``MINIO_*`(容器内需访问 `MINIO_ENDPOINT`,默认已通过 `DOCKER_MINIO_ENDPOINT` 指向 `minio:9000`)。
- `OR_SITE_CONFIG_JSON_FILE`:容器内可读路径下的站点 JSON若在宿主机维护**`volumes`** 挂载进 `api` 容器(挂载方式由项目单独约定)。
- RTSP`host.docker.internal` 用于访问**宿主机**上的假流;详见 `docs/video-backends.md`
---
## 六、启动与健康检查
```bash
docker compose up -d
docker compose ps
curl -sf http://127.0.0.1:38080/health
```
局域网终端将「服务端 Base URL」配置为`http://<服务器局域网IP>:38080`(若修改了 `API_PORT` 则同步修改端口)。
查看日志:
```bash
docker compose logs -f api
```
---
## 七、升级 API 镜像
1. 客户停止 API或整栈`docker compose stop api`
2. 加载新 tarball`docker load -i …`
3.`docker-compose.yml``api.image` 更新为新 `<交付镜像名>:<新版本号>`(或保持不变若标签滚动更新,需先在客户机 `docker rmi` 旧镜像或使用明确版本标签)。
4. `docker compose up -d`。API 容器启动仍会执行 `alembic upgrade head`
---
## 八、常见问题
**Q`docker compose up` 仍尝试 build**
A`api` 服务仍存在 `build:` 配置时会构建。必须使用本文第四节模板,仅用 `image:`
**Q无 GPU 报错?**
A本仓库默认要求 GPU 推理。若必须在无 GPU 环境运行,需移除 `api``gpus: all` 并使用 CPU 兼容镜像(推理会显著变慢,需与厂商确认)。
**QPostgreSQL / MinIO 数据在哪?**
ADocker 命名卷(如 `pgdata``minio_data``docker compose down -v` 会删除数据,操作前确认备份。
**Q`host.docker.internal` 在 Linux 无效?**
ACompose 已为 `api` 配置 `extra_hosts: host.docker.internal:host-gateway`Docker 20.10+)。若自定义运行 `docker run`,需自行添加同等 `extra_hosts`
---
## 九、与安全相关
- tarball 等价于可复制软件制品,分发渠道注意保密与校验(校验和、签名)。
- 勿将生产密钥写入镜像层;一律通过 `.env` 或编排系统注入运行时环境变量。
如需语音确认前端、演示客户端与本后端的局域网访问说明,参见 `docs/Docker部署.md``clients/voice-confirmation/README.md``clients/demo-client/README.md`