将后端迁入 backend/,完善根目录 .gitignore,删除误提交的 .mypy_cache 缓存文件。 Co-authored-by: Cursor <cursoragent@cursor.com>
274 lines
11 KiB
Markdown
Executable File
274 lines
11 KiB
Markdown
Executable File
# 离线镜像(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 兼容镜像(推理会显著变慢,需与厂商确认)。
|
||
|
||
**Q:PostgreSQL / MinIO 数据在哪?**
|
||
A:Docker 命名卷(如 `pgdata`、`minio_data`);`docker compose down -v` 会删除数据,操作前确认备份。
|
||
|
||
**Q:`host.docker.internal` 在 Linux 无效?**
|
||
A:Compose 已为 `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`。
|