e76360dbc4
Полный комплект документации к Phase 11b:
docs/ru/user.md — для админа инсталляции (motion-mode, PTZ,
templates.json, mqtt_overlays.json, ZMQ verbs)
docs/ru/developer.md — архитектура (Cell / Layout / Decoration),
как добавить новый Cell/Decoration, ABI shim,
algorithms (best-fit + asymmetric hysteresis)
docs/ru/operations.md — build (host + jammy + incremental bake),
deploy, logs/telemetry, troubleshooting
(broken pipe, MQTT-overlay, motion-mode)
docs/en/*.md — английская версия всех трёх
README.md — переписан с overview + ссылками на docs/
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
405 lines
15 KiB
Markdown
405 lines
15 KiB
Markdown
# cfc-grid — operations / deploy / troubleshooting
|
||
|
||
> Аудитория: тот кто билдит, деплоит, мониторит cfc-grid в проде.
|
||
>
|
||
> Если ты пользователь — см. [user.md](user.md). Если разработчик —
|
||
> см. [developer.md](developer.md).
|
||
|
||
## 1. Production setup (R9-88.23)
|
||
|
||
### 1.1 Стек
|
||
|
||
```
|
||
docker compose -f docker-compose.yml \
|
||
-f cuda-grid/docker-compose.override.yml \
|
||
-f cuframes-composer/docker-compose.override.yml \
|
||
-f onvif/docker-compose.override.yml \
|
||
up -d
|
||
```
|
||
|
||
Файлы — в `localhost-infra/hosts/R9-88.23/docker/cctv/`.
|
||
|
||
| Сервис | Image | Назначение |
|
||
|---|---|---|
|
||
| `cuframes-ipc-anchor` | `gx/cuframes:0.4` | Shared VMM IPC anchor для cuframes |
|
||
| `cuframes-pub-*` (parking/back_yard/front_yard/gate_lpr) | `gx/cuframes:0.4` | RTSP → cuframes per-camera publishers |
|
||
| `cuda-grid-mediamtx` | `bluenviron/mediamtx` | RTSP/HLS/WebRTC gateway |
|
||
| `cctv-mosquitto` | `eclipse-mosquitto` | MQTT broker (+bridge к 192.168.88.4) |
|
||
| **`cfc-grid`** | `gx/cuframes-composer:0.11b-step1` | Композитор (главный сервис) |
|
||
| `cfc-grid-ffmpeg` | `ffmpeg-vf-cuda-grid:phase4b-final` | H.264 pipe → RTSP push |
|
||
| `cfc-grid-watchdog` | `gx/cuda-grid-watchdog:0.4` | Restart cfc-grid при stuck inboundBytes |
|
||
| `cctv-onvif` | `gx/cctv-onvif:0.6` | ONVIF discovery + PTZ → ZMQ |
|
||
| `cctv-frigate` | `ghcr.io/blakeblackshear/frigate` | Object detection → MQTT events |
|
||
|
||
### 1.2 Поток кадров
|
||
|
||
```
|
||
cuframes-pub-X ──VMM──┐
|
||
cuframes-pub-Y ──VMM──┼──→ cfc-grid (composer)
|
||
cuframes-pub-Z ──VMM──┘ │
|
||
│ H.264 NVENC
|
||
↓ named pipe /tmp/cfc-pipe-dir/grid.h264
|
||
cfc-grid-ffmpeg (re-mux)
|
||
│ RTSP push
|
||
↓
|
||
cuda-grid-mediamtx
|
||
rtsp://*/cfc-grid (TCP/UDP)
|
||
http://*:8888/cfc-grid (HLS)
|
||
http://*:8889/cfc-grid (WebRTC)
|
||
```
|
||
|
||
### 1.3 Сети
|
||
|
||
- Внутренний docker network: `cctv`
|
||
- Внешние порты на R9-88.23:
|
||
- `554/tcp` — RTSP (mediamtx)
|
||
- `8888/tcp` — HLS (mediamtx)
|
||
- `8889/tcp` — WebRTC (mediamtx)
|
||
- `5599/tcp` — ZMQ control plane composer'а
|
||
- `8085/tcp` — ONVIF SOAP (cctv-onvif)
|
||
- `3702/udp` — WS-Discovery multicast (cctv-onvif)
|
||
|
||
## 2. Build
|
||
|
||
### 2.1 Local host build (Ubuntu 24.04, dev машина)
|
||
|
||
```bash
|
||
cd /home/claude/projects/cuframes-composer
|
||
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||
cmake --build build -j$(nproc)
|
||
```
|
||
|
||
Артефакты в `build/src/libcuframes_composer.so` и `build/examples/grid_record`.
|
||
|
||
**ВАЖНО:** host'овый бинарь (Ubuntu 24.04, glibc 2.39, libavformat60)
|
||
**несовместим** с runtime контейнером (Ubuntu 22.04 jammy, glibc 2.35,
|
||
libavformat58). См. memory `incremental-ffmpeg-rebuild`.
|
||
|
||
### 2.2 Jammy build (для production image)
|
||
|
||
Использует кешированный builder-контейнер `cuframes-composer-builder:cached`
|
||
(Ubuntu 22.04 + nvidia/cuda:12.4.1-devel + apt-deps):
|
||
|
||
```bash
|
||
cd /home/claude/projects/cuframes-composer
|
||
|
||
# Если builder ещё не закеширован:
|
||
docker image inspect cuframes-composer-builder:cached >/dev/null 2>&1 || {
|
||
docker run -d --name cfc-builder-tmp \
|
||
nvidia/cuda:12.4.1-devel-ubuntu22.04 sleep 3600
|
||
docker exec cfc-builder-tmp bash -c '
|
||
apt-get update -qq && apt-get install -y -qq --no-install-recommends \
|
||
build-essential cmake git pkg-config \
|
||
libpng-dev libfreetype-dev \
|
||
libzmq3-dev libjson-c-dev libmosquitto-dev \
|
||
libavformat-dev libavcodec-dev libavutil-dev'
|
||
docker commit cfc-builder-tmp cuframes-composer-builder:cached
|
||
docker rm -f cfc-builder-tmp
|
||
}
|
||
|
||
# Сам build:
|
||
docker run --rm --gpus all -v "$PWD":/src -w /src/build-jammy \
|
||
cuframes-composer-builder:cached \
|
||
bash -c 'cmake -DCMAKE_BUILD_TYPE=Release .. && make -j$(nproc)'
|
||
```
|
||
|
||
Артефакты в `build-jammy/`.
|
||
|
||
### 2.3 Bake image (incremental — без `docker build`)
|
||
|
||
Не используем `docker build` (4GB CUDA pull при cache miss). Вместо:
|
||
|
||
```bash
|
||
docker rmi gx/cuframes-composer:0.11b-step1 -f 2>/dev/null
|
||
CID=$(docker create gx/cuframes-composer:0.10)
|
||
docker cp build-jammy/examples/grid_record "$CID":/usr/local/bin/grid_record
|
||
docker cp build-jammy/src/libcuframes_composer.so.0.1.0 \
|
||
"$CID":/usr/lib/x86_64-linux-gnu/libcuframes_composer.so.0
|
||
docker cp docker/templates.json "$CID":/opt/templates.json
|
||
docker cp docker/mqtt_overlays.json "$CID":/opt/mqtt_overlays.json
|
||
docker commit \
|
||
--change 'ENTRYPOINT ["/usr/local/bin/grid_record"]' \
|
||
--change 'CMD ["--help"]' \
|
||
--change 'ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility,video' \
|
||
"$CID" gx/cuframes-composer:0.11b-step1
|
||
docker rm "$CID"
|
||
```
|
||
|
||
Использует базу `gx/cuframes-composer:0.10` (с уже установленными runtime
|
||
deps) + накладывает свежие артефакты. Быстрее и без сетевого трафика.
|
||
|
||
### 2.4 Build ONVIF image
|
||
|
||
```bash
|
||
cd hosts/R9-88.23/docker/cctv/onvif
|
||
docker build -t gx/cctv-onvif:0.6 -f Dockerfile .
|
||
```
|
||
|
||
Python image, лёгкий. Если меняешь `server.py` — rebuild image (тег
|
||
поднимать) + правишь image в `docker-compose.override.yml`.
|
||
|
||
## 3. Deploy
|
||
|
||
### 3.1 Прод (R9-88.23)
|
||
|
||
```bash
|
||
cd /home/claude/projects/localhost-infra/hosts/R9-88.23/docker/cctv
|
||
docker compose -f docker-compose.yml \
|
||
-f cuda-grid/docker-compose.override.yml \
|
||
-f cuframes-composer/docker-compose.override.yml \
|
||
-f onvif/docker-compose.override.yml \
|
||
up -d cfc-grid
|
||
```
|
||
|
||
Compose автоматически recreate'нет контейнер если image tag поменялся в
|
||
`docker-compose.override.yml`.
|
||
|
||
### 3.2 Verify post-deploy
|
||
|
||
```bash
|
||
# Logs композитора
|
||
docker logs --tail 30 cfc-grid 2>&1 | grep -iE "loaded|template|pool|motion"
|
||
|
||
# Ожидаем что-то типа:
|
||
# [cfc/loader] /opt/templates.json: loaded 9 templates
|
||
# [cfc/composer] templates loaded: 9 (path='/opt/templates.json')
|
||
# [cfc/composer] pool+ 'cam-parking' (frigate=parking_overview prio=100)
|
||
# [cfc/composer] motion_mode=1 ttl=45000ms pool=4
|
||
# [cfc/composer] grow → template='tpl_3' active=3
|
||
```
|
||
|
||
### 3.3 Rollback
|
||
|
||
```bash
|
||
sed -i 's|gx/cuframes-composer:0.11b-step1|gx/cuframes-composer:0.10|' \
|
||
hosts/R9-88.23/docker/cctv/cuframes-composer/docker-compose.override.yml
|
||
docker compose ... up -d cfc-grid
|
||
```
|
||
|
||
## 4. Logs
|
||
|
||
### 4.1 Live tail
|
||
|
||
```bash
|
||
docker logs -f --tail 50 cfc-grid
|
||
docker logs -f --tail 30 cfc-grid-ffmpeg
|
||
docker logs -f --tail 30 cuda-grid-mediamtx
|
||
docker logs -f --tail 30 cctv-onvif
|
||
docker logs -f --tail 30 cctv-frigate
|
||
```
|
||
|
||
### 4.2 Telemetry pattern
|
||
|
||
| Маркер | Что значит |
|
||
|---|---|
|
||
| `[grid_record] N кадров, M IDR, X МБ за Y.0с (25.0 fps)` | Composer успешно encode'ит каждые ~50 кадров |
|
||
| `[cfc/composer] grow → template='X'` | Применился новый template (расширение, мгновенно) |
|
||
| `[cfc/composer] shrink → template='X'` | Применился новый template после hysteresis (сжатие) |
|
||
| `[cfc/composer] manual override 'X' до +60000ms` | PTZ через ONVIF |
|
||
| `[cfc/composer] manual override expired, возврат в motion-mode` | Auto-возврат после 60s |
|
||
| `[cfc/mqtt-overlay/<id>] '<text>'` | MQTT-overlay получил/отрендерил новый text |
|
||
| `[cfc/frigate] connected, subscribe 'frigate/events'` | Frigate-subscriber подключился |
|
||
| `[cfc/temp] update: 'XX.X°C'` | (старый код, deprecated — теперь mqtt-overlay) |
|
||
|
||
### 4.3 Когда что-то сломалось
|
||
|
||
| Симптом | Где искать |
|
||
|---|---|
|
||
| `src active=0 stale=0 dead=4` | cuframes-pub-* контейнеры; проверь `docker ps` и сетевой доступ к камерам |
|
||
| `overlay 0 draw failed` | `cfc_overlay_text_rebuild_atlas` — обычно невалидный шрифт или текст |
|
||
| RTSP стрим не отдаёт | `cfc-grid-ffmpeg` логи; смотри §6.1 |
|
||
| TV/ONVIF не находит | `cctv-onvif` логи; проверь multicast WS-Discovery в LAN |
|
||
|
||
## 5. Monitoring
|
||
|
||
### 5.1 MQTT health
|
||
|
||
`cfc-grid` публикует health в `cuda_grid/health/composer/cfc-grid`
|
||
каждые ~10 секунд:
|
||
|
||
```json
|
||
{
|
||
"uptime_s": 3600,
|
||
"frames_encoded": 90000,
|
||
"fps_actual": 25.0,
|
||
"bitrate_kbps": 6000,
|
||
"src_active": 4,
|
||
"src_stale": 0,
|
||
"src_dead": 0,
|
||
"idr_count": 1
|
||
}
|
||
```
|
||
|
||
```bash
|
||
PW=$(grep '^COMPOSER_MQTT_PASSWORD=' \
|
||
/home/claude/projects/localhost-infra/hosts/R9-88.23/docker/cctv/.env | cut -d= -f2)
|
||
mosquitto_sub -h 192.168.88.23 -u composer -P "$PW" \
|
||
-t 'cuda_grid/health/composer/cfc-grid' -v
|
||
```
|
||
|
||
### 5.2 Watchdog
|
||
|
||
`cfc-grid-watchdog` — отдельный сервис, мониторит mediamtx
|
||
`inboundBytes` для пути `cfc-grid`. Если **30 секунд молчания** —
|
||
`docker restart cfc-grid`.
|
||
|
||
Логи watchdog'а:
|
||
```bash
|
||
docker logs --tail 30 cfc-grid-watchdog
|
||
```
|
||
|
||
При срабатывании — публикует в `cuda_grid/health/watchdog/cfc-grid`.
|
||
|
||
## 6. Troubleshooting
|
||
|
||
### 6.1 RTSP не отдаёт / `cfc-grid-ffmpeg` в "Broken pipe"
|
||
|
||
**Симптом:** `docker logs cfc-grid-ffmpeg` показывает
|
||
`[out#0/rtsp] Task finished with error code: -32 (Broken pipe)`.
|
||
|
||
**Причина:** `--intra-refresh` в composer'е (без IDR-burst'ов), mediamtx
|
||
рвёт RTSP-publisher если не может отдать новому клиенту start-frame.
|
||
|
||
**Лечение:**
|
||
- Полный restart pipeline:
|
||
```bash
|
||
docker compose ... restart cfc-grid-ffmpeg cfc-grid cuda-grid-mediamtx
|
||
```
|
||
- Если повторяется — отключить `--intra-refresh` в compose override
|
||
(стоимость: IDR-bursts в bitrate, но стабильнее для downstream
|
||
клиентов с frequent disconnect/reconnect)
|
||
|
||
### 6.2 ffmpeg не получает кадры от RTSP
|
||
|
||
**Симптом:** при `ffmpeg -i rtsp://192.168.88.23:554/cfc-grid -frames:v 1 out.jpg`
|
||
зависает на 30+ секунд.
|
||
|
||
**Причина:** Composer пишет H.264 без regular IDR (intra-refresh). Новый
|
||
RTSP-клиент ждёт keyframe для старта декодинга. ffmpeg в default
|
||
конфигурации не ждёт достаточно долго.
|
||
|
||
**Workaround:**
|
||
```bash
|
||
ffmpeg -rtsp_transport tcp \
|
||
-analyzeduration 10000000 -probesize 10000000 \
|
||
-i rtsp://192.168.88.23:554/cfc-grid \
|
||
-frames:v 1 -y out.jpg
|
||
```
|
||
|
||
Или используй HLS:
|
||
```bash
|
||
ffmpeg -i http://192.168.88.23:8888/cfc-grid/index.m3u8 \
|
||
-frames:v 1 -y out.jpg
|
||
```
|
||
|
||
### 6.3 MQTT-overlay не обновляется
|
||
|
||
**Чек-лист:**
|
||
|
||
1. Бридж к HA broker (192.168.88.4) работает?
|
||
```bash
|
||
docker logs cctv-mosquitto 2>&1 | grep -i 'bridge'
|
||
```
|
||
Ищи `Connecting bridge ha-bridge` и подтверждение connect.
|
||
|
||
2. Нужный topic в bridge config?
|
||
```bash
|
||
docker exec cctv-mosquitto grep 'topic.*in 0' /mosquitto/config/mosquitto.conf
|
||
```
|
||
Если новый префикс — добавь `topic XXX/# in 0` и restart mosquitto.
|
||
|
||
3. Subscriber подключился?
|
||
```bash
|
||
docker logs cfc-grid 2>&1 | grep 'mqtt-overlay/<id>.*connected'
|
||
```
|
||
|
||
4. Тестовый publish:
|
||
```bash
|
||
mosquitto_pub -h 192.168.88.4 -t '<твой topic>' -m 'test' -r
|
||
```
|
||
В логах composer'а должно появиться `[cfc/mqtt-overlay/<id>] 'test'`.
|
||
|
||
### 6.4 Motion-mode не переключает layout
|
||
|
||
**Чек-лист:**
|
||
|
||
1. Frigate шлёт events?
|
||
```bash
|
||
mosquitto_sub -h 192.168.88.23 -u composer -P "$PW" \
|
||
-t 'frigate/events' -C 3
|
||
```
|
||
|
||
2. Composer получает events?
|
||
```bash
|
||
docker logs cfc-grid 2>&1 | grep 'frigate.*started\|grow\|shrink'
|
||
```
|
||
|
||
3. Camera-name матчится?
|
||
`frigate=<имя>` в `--source` должно совпадать с `event.after.camera`.
|
||
|
||
4. Zone-filter не отсекает?
|
||
Если `zones=A:B:C` в `--source` — посмотри в Frigate event
|
||
`current_zones`. Если пусто или не пересекается — pulse отбрасывается.
|
||
|
||
5. TTL не истёк?
|
||
Logs `motion_ttl=45000` (45 сек) — если события приходят реже —
|
||
камера выпадает из active.
|
||
|
||
### 6.5 ONVIF PTZ presets пусты в TV
|
||
|
||
**Причина:** TV закешировал старый ответ `GetPresets` (Phase 9 имена).
|
||
|
||
**Лечение:** удалить и заново добавить камеру в TV-клиенте.
|
||
|
||
### 6.6 Templates загрузились но motion-mode не использует новый
|
||
|
||
Composer читает global registry `cfc::current_templates()` на каждом
|
||
кадре — изменение через `cfc_layout_load_file` (ZMQ или CLI) должно
|
||
быть подхвачено сразу. Если нет — проверь:
|
||
|
||
```bash
|
||
echo '{"cmd":"list_layouts"}' | python3 -c "
|
||
import zmq,json,sys
|
||
s = zmq.Context().socket(zmq.REQ)
|
||
s.connect('tcp://192.168.88.23:5599')
|
||
s.send_json({'cmd':'list_layouts'})
|
||
print(json.dumps(s.recv_json(), indent=2, ensure_ascii=False))"
|
||
```
|
||
|
||
Поле `source` показывает текущий загруженный path. Если built-in (только
|
||
`tpl_1` + `tpl_4`) — JSON не подгрузился (syntax error, кривой path).
|
||
|
||
## 7. Конфиги в репо
|
||
|
||
| Что | Где |
|
||
|---|---|
|
||
| templates.json | `cuframes-composer/docker/templates.json` |
|
||
| mqtt_overlays.json | `cuframes-composer/docker/mqtt_overlays.json` |
|
||
| compose override | `localhost-infra/hosts/R9-88.23/docker/cctv/cuframes-composer/docker-compose.override.yml` |
|
||
| ONVIF config | `localhost-infra/.../onvif/onvif.yaml` |
|
||
| ONVIF server | `localhost-infra/.../onvif/server.py` |
|
||
| Mosquitto config | `localhost-infra/.../cctv/mosquitto/config/mosquitto.conf` |
|
||
| .env (passwords) | `localhost-infra/.../cctv/.env` (gitignored) |
|
||
|
||
После изменения compose override — `docker compose ... up -d cfc-grid`
|
||
автоматически recreate'нет.
|
||
|
||
## 8. Известные ограничения / TODO
|
||
|
||
- **`--intra-refresh` ↔ RTSP-clients**: trade-off bitrate vs latency
|
||
(см. §6.1)
|
||
- **Watchdog только cfc-grid**: cfc-grid-ffmpeg в зомби-state не
|
||
детектится напрямую; помогает только полный restart
|
||
- **Hot-reload mqtt_overlays.json**: нет ZMQ verb'а
|
||
- **MQTT-overlay per-broker config**: всё через один broker; для
|
||
внешнего broker'а нужно расширить `MqttBrokerCfg` per-item
|
||
|
||
## 9. См. также
|
||
|
||
- [user.md](user.md) — настройка композитора
|
||
- [developer.md](developer.md) — внутренности, добавление модулей
|
||
- `memory/host-and-project.md` — общая инфра R9-88.23
|
||
- `memory/project_cfc-grid-deployed.md` — deploy 1-го прода
|
||
- `memory/project_cfc-grid-cpp-refactor.md` — Phase 11b refactor
|
||
- `memory/incremental-ffmpeg-rebuild.md` — incremental docker recipe
|