将后端迁入 backend/,完善根目录 .gitignore,删除误提交的 .mypy_cache 缓存文件。 Co-authored-by: Cursor <cursoragent@cursor.com>
11 KiB
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. 构建并打标签
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 服务器,需启用跨平台构建(示例):
docker buildx build --platform linux/amd64 -t <交付镜像名>:<版本号> --load .
2. 导出为 tarball
单机文件交付常用压缩包:
docker save <交付镜像名>:<版本号> | gzip -9 > or-monitor-api_<版本号>_linux-amd64.tar.gz
导出多个镜像(可选,用于 完全离线 且客户机不能拉 Postgres/MinIO 时):
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 拷贝到服务器后:
gzip -dc or-monitor-api_<版本号>_linux-amd64.tar.gz | docker load
# 或:docker load -i or-monitor-api_<版本号>_linux-amd64.tar
确认镜像已存在:
docker images | grep <交付镜像名>
若为「全栈离线包」,同样对整体 tar.gz 执行一次 docker load 即可导入多个镜像。
四、客户侧:Compose 配置(使用已加载镜像)
在部署目录放置 docker-compose.yml,将 api 服务改为使用预加载镜像,不要保留 build:。可直接使用下面模板(把镜像名与版本改成实际交付值):
# 与仓库主 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。
六、启动与健康检查
docker compose up -d
docker compose ps
curl -sf http://127.0.0.1:38080/health
局域网终端将「服务端 Base URL」配置为:http://<服务器局域网IP>:38080(若修改了 API_PORT 则同步修改端口)。
查看日志:
docker compose logs -f api
七、升级 API 镜像
- 客户停止 API(或整栈):
docker compose stop api。 - 加载新 tarball:
docker load -i …。 - 将
docker-compose.yml中api.image更新为新<交付镜像名>:<新版本号>(或保持不变若标签滚动更新,需先在客户机docker rmi旧镜像或使用明确版本标签)。 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。