Развёртывание устройства Iris (Appliance Deployment)¶
Документ описывает развёртывание запечатанного устройства Iris VMS на площадке клиента. Iris поставляется как аппаратно-программный комплекс (мы отгружаем железо вместе с ПО): сервер с одним GPU класса NVIDIA T4/L4 и предустановленным образом Iris. Сценарий рассчитан на изолированную (air-gap) сеть — runtime не требует доступа в интернет.
Связанные документы: DEPLOYMENT.md (общее развёртывание), SECURITY.md (модель безопасности),
LICENSING.md (лицензирование и риск моделей), ARCHITECTURE.md.
1. Аппаратные и системные требования¶
| Компонент | Требование |
|---|---|
| GPU | Один NVIDIA класса T4/L4, 16 ГБ |
| Драйвер хоста | Поддержка CUDA 12.4 |
| Container runtime | Docker + NVIDIA Container Toolkit |
| Хранилище | Диск под data/ (записи, сегменты, эскизы, образцы лиц); рекомендуется LUKS full-disk |
| ОС | Linux-хост с поддержкой Docker Compose |
GPU обязателен для AI-конвейера (детекция YOLO, распознавание лиц, re-ID). Драйвер хоста должен быть совместим с CUDA 12.4, а NVIDIA Container Toolkit — пробрасывать GPU в контейнер.
Проверка доступности GPU на хосте перед установкой:
Резервный режим без GPU (GPU-eviction fallback)¶
Если GPU недоступен (вытеснен, отказ драйвера, диагностика), runtime можно перевести на CPU, установив:
Это деградированный режим для поддержания доступности; производительность AI-конвейера будет существенно ниже.
2. Состав поставки и запечатанный образ¶
Устройство поставляется с запечатанным Docker-образом, выгруженным через docker save в tar-архив и
подписанным поставщиком. На площадке образ проверяется по подписи и загружается локально — без обращения
к внешним реестрам.
# Проверка подписи поставки (по приложенной подписи и публичному ключу поставщика)
# затем загрузка образа в локальный Docker
docker load -i iris-appliance-<version>.tar
docker image ls | grep iris
В состав поставки входят:
- запечатанный образ контейнеров
vmsиvms-scanner; - каталог
models/с локально закэшированными моделями (детекция, лица, re-ID, аудио); - образы LAN-сайдкаров AI (опционально, см. §4);
- per-unit заготовка
data/и файлы конфигурации (.env).
3. Засев моделей и per-unit данных¶
models/¶
AI-модели кэшируются локально и не скачиваются в рантайме. Каталог models/ входит в поставку и монтируется
в контейнер vms. Для гарантии офлайн-работы выставьте флаги офлайн-режима Hugging Face:
Возрастно-гендерная модель MiVOLO теперь учитывает local_files_only, поэтому при выставленных флагах ни одна
часть конвейера не пытается обращаться в сеть.
Дополнительно включите офлайн-режим приложения, который отключает единственные две интернет-зависимые функции — поиск камер через Shodan и приём веб-ссылок через yt-dlp:
data/ (per-unit)¶
data/ — это per-unit состояние конкретного устройства: SQLite-БД (единственный источник истины, режим WAL),
записи, сегменты, эскизы, образцы лиц. Каталог создаётся при первом запуске и должен лежать на зашифрованном
(LUKS) разделе. .env, data/ и models/ не входят в систему контроля версий и содержат конфиденциальные
артефакты — обращайтесь с ними соответственно.
4. Контейнеры и LAN-сайдкары AI¶
Два основных контейнера¶
vms— FastAPI API + менеджеры фоновых задач + по одному worker-подпроцессу на камеру.vms-scanner— изолированный от сбоев контейнер обнаружения/аудита (он не открывает живые камеры, что защищает основной сервис).
Запуск стека:
Опциональные AI-сайдкары (LAN, fail-open)¶
Расширенный AI-функционал обеспечивают сайдкары, развёрнутые в локальной сети и работающие по принципу fail-open (их отсутствие не ломает основной сервис):
| Сайдкар | Назначение | Порт (LAN) |
|---|---|---|
| whisper-xtts | STT (распознавание речи) | :8000 |
| ollama + EuroLLM | перевод | :11434 |
| xtts | дубляж | — |
| mediamtx | браузерная камера (browser-cam) | — |
Все сайдкары хостятся в LAN и не требуют выхода в интернет.
Резервные копии¶
Скрипты резервного копирования (scripts/backup_*.sh через rclone) перенаправляются на локальный (on-prem)
MinIO через переменную S3_ENDPOINT — данные не покидают площадку.
5. Сетевая схема¶
API контейнера vms биндится только на loopback 127.0.0.1:8120. Внешний доступ обеспечивает
встроенный обратный прокси (nginx), который терминирует TLS и выполняет SSO-проверку, прокидывая
доверенный заголовок идентичности.
[ Клиент ] --HTTPS--> [ nginx (TLS + SSO) ] --HTTP--> [ 127.0.0.1:8120 vms API ]
|
[ data/ (SQLite WAL, медиа) ]
|
LAN AI-сайдкары: whisper-xtts:8000, ollama:11434, mediamtx, xtts
Аутентификация сегодня основана на доверенном SSO-заголовке X-Email (он переопределяет любое значение,
присланное клиентом, — защита от подмены). Встроенного логина/ролей пока нет — это запланированный пункт (WS2).
Безопасность устройства¶
Уже реализовано:
- контейнер выполняется non-root (uid 1000),
cap_drop: ALL,no-new-privileges; - исходники смонтированы read-only; все записи идут в
data/; - API доступен только через loopback за nginx;
- шифрование секретов at-rest (
app/crypto.py): чувствительные поля (например,cameras.onvif_password) шифруются по схеме stdlib HMAC-CTR + encrypt-then-MAC; ключ берётся изIRIS_SECRET_KEYлибо изdata/secret.key(права0600) и никогда не хранится в БД; - LUKS full-disk — основной механизм защиты данных at-rest.
6. Первичная настройка (first-boot)¶
После загрузки образа и запуска стека:
- Сеть. Настройте сетевые параметры хоста и доступ к LAN, где находятся камеры и AI-сайдкары.
- TLS / прокси. Установите сертификат в встроенный обратный прокси; проверьте, что внешний доступ идёт только по HTTPS.
- Администратор / идентичность. Настройте источник SSO-заголовка
X-Emailдля административного доступа (встроенных логина/ролей пока нет — WS2). - Ключ секретов. Убедитесь, что задан
IRIS_SECRET_KEYили сгенерированdata/secret.key(0600) — без него поля секретов at-rest не защищены. - Офлайн-флаги. Выставьте
HF_HUB_OFFLINE=1,TRANSFORMERS_OFFLINE=1,offline_mode = true. - Камеры. Добавьте камеры через ingest RTSP/ONVIF; при необходимости используйте обнаружение
(
vms-scanner). Учётные данные ONVIF шифруются at-rest. - Лицензия (опционально). При включённом enforcement установите подписанную лицензию (см. §8).
7. Проверка работоспособности (smoke-check)¶
Базовая проверка живости — неаутентифицированный эндпоинт /health:
Дополнительно проверьте:
# контейнеры подняты
docker compose ps
# GPU виден внутри контейнера vms (если не используется DETECTOR_DEVICE=cpu)
nvidia-smi
После этого убедитесь, что внешний HTTPS-доступ через прокси работает, а добавленные камеры дают живой поток
и события записываются (ffmpeg -c copy, ~0% CPU).
8. Лицензирование (опционально, по умолчанию выключено)¶
Подсистема лицензирования (app/licensing/) поставляется инертной; принудительное применение включается
настройкой license_enforce. Лицензия — подписанный JSON:
{
"payload": {
"license_id": "...",
"customer": "...",
"issued": "...",
"expires": "...",
"max_cameras": 0,
"modules": ["faces", "reid", "audit", "audio", "subtitles", "ptz", "analytics"],
"hardware": "...",
"hardware_fields": ["gpu", "machine-id", "product_uuid"],
"heartbeat": { "required": false, "grace_days": 0, "url": "..." }
},
"sig": "base64..."
}
- Подпись: RSA-PKCS1v15-SHA256, проверяется средствами stdlib (
app/licensing/rsa_verify.py) с публичным ключом поставщика изIRIS_LICENSE_PUBKEY_N/IRIS_LICENSE_PUBKEY_E. - Отпечаток оборудования (
app/licensing/fingerprint.py): SHA-256 по выбранным полям; по умолчанию GPU (UUID изnvidia-smi) +machine-id+ DMIproduct_uuid. - Гейт функций (
app/licensing/gate.py): пустойmodules= все модули; иначе только перечисленные;max_camerasограничивает число камер. - Модель — offline-first: подписанная лицензия валидна локально; heartbeat опционален и работает с grace-периодом.
9. Замечание о лицензиях моделей (release-gate, отложено)¶
Перед коммерческой отгрузкой следует учитывать риск лицензий используемых моделей: YOLOv8 (AGPL),
InsightFace buffalo_l (non-commercial), OSNet/MSMT17 (research-only). On-prem поставка — наихудший сценарий
по этим лицензиям. Это release-gate, решение по которому отложено (accepted risk); путь устранения
описан в docs/LICENSING.md (замена на RTMDet/RT-DETR + DINOv2; лицензирование либо отсрочка распознавания лиц).