fbe1d18c39
- docs/troubleshooting.md — 13 секций с реальными grабельками которые мы прошли: cudaIpcOpenEventHandle invalid device context (pid namespace), s6-overlay vs pid share, scale_cuda missing (cuda-llvm + stdbit.h glibc 2.36), libcuframes not found install paths, ffbuild/ missing source, GMP no working compiler (long-long reliability), zlib.net deprecated URL, RTSP/RTP UDP docker NAT, gitea actions Node version - docs/architecture.md — Appendix A "Production deployment notes" с реальными observations после 24h+ run: что подтвердилось, что доработали, что не учли - docs/requirements.md — production deployment matrix + Docker namespace requirements таблица (cross-container CUDA IPC требует 5 условий) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
327 lines
16 KiB
Markdown
327 lines
16 KiB
Markdown
# Troubleshooting
|
||
|
||
Реальные грабли которые мы прошли при первой production deployment'е cuframes
|
||
(Frigate + custom C++ processor + custom Python). Документировано чтобы вы их
|
||
не повторяли.
|
||
|
||
## Содержание
|
||
|
||
- [Runtime / CUDA IPC](#runtime--cuda-ipc)
|
||
- [`cudaIpcOpenEventHandle: invalid device context`](#cudaipcopeneventhandle-invalid-device-context)
|
||
- [Subscriber timeout (`cuframes_subscriber_create: timeout`)](#subscriber-timeout)
|
||
- [Permission denied на socket](#permission-denied-на-socket)
|
||
- [Frigate-specific](#frigate-specific)
|
||
- [`s6-overlay-suexec: fatal: can only run as pid 1`](#s6-overlay-suexec-fatal-can-only-run-as-pid-1)
|
||
- [`No such filter: 'scale_cuda'`](#no-such-filter-scale_cuda)
|
||
- [Missing dynamic .so после ffmpeg replace](#missing-dynamic-so-после-ffmpeg-replace)
|
||
- [Build / FFmpeg patch](#build--ffmpeg-patch)
|
||
- [`libcuframes not found` при configure](#libcuframes-not-found-при-configure)
|
||
- [`ffbuild/library.mak: No such file`](#ffbuildlibrarymak-no-such-file)
|
||
- [`could not find a working compiler` (GMP)](#could-not-find-a-working-compiler-gmp)
|
||
- [`zlib: download failed` в crosstool-NG](#zlib-download-failed-в-crosstool-ng)
|
||
- [`stdbit.h: No such file` при `--enable-cuda-llvm`](#stdbith-no-such-file-при---enable-cuda-llvm)
|
||
- [Docker / IPC](#docker--ipc)
|
||
- [Cross-container CUDA IPC: ipc + pid namespace share](#cross-container-cuda-ipc-ipc--pid-namespace-share)
|
||
- [Buildx container driver не видит host images](#buildx-container-driver-не-видит-host-images)
|
||
- [Networking / RTSP](#networking--rtsp)
|
||
- [RTSP/RTP UDP не доходит до клиента (docker NAT)](#rtsprtp-udp-не-доходит-до-клиента-docker-nat)
|
||
- [`Nonmatching transport in server reply`](#nonmatching-transport-in-server-reply)
|
||
- [Gitea Actions / CI](#gitea-actions--ci)
|
||
- [`node: executable file not found`](#node-executable-file-not-found)
|
||
- [`SyntaxError: Unexpected token '{'` (Node 12)](#syntaxerror-unexpected-token--node-12)
|
||
|
||
---
|
||
|
||
## Runtime / CUDA IPC
|
||
|
||
### `cudaIpcOpenEventHandle: invalid device context`
|
||
|
||
**Симптом**: subscriber сразу после `cuframes_subscriber_create` падает с этой ошибкой.
|
||
|
||
**Причина**: CUDA driver проверяет IPC peer через `/proc/<pid>/...`. Если процесс publisher'а **не виден** в PID namespace consumer'а — context считается невалидным.
|
||
|
||
**Fix**: shared PID namespace.
|
||
|
||
Docker:
|
||
```yaml
|
||
consumer:
|
||
ipc: "container:<publisher>" # shared /dev/shm
|
||
pid: "container:<publisher>" # ← вот это критично, без него fail
|
||
```
|
||
|
||
Host process: запуск consumer'а на host'е (либо publisher'а на host'е тоже) — same default namespace.
|
||
|
||
**Caveat**: если consumer image использует s6-overlay (Frigate, linuxserver.io
|
||
images) — `pid: container:` несовместим (см. [соответствующую секцию](#s6-overlay-suexec-fatal-can-only-run-as-pid-1)).
|
||
|
||
### Subscriber timeout
|
||
|
||
**Симптом**: `cuframes_subscriber_create: timeout` без других ошибок.
|
||
|
||
**Причины** (в порядке вероятности):
|
||
1. `/run/cuframes/<key>.sock` не виден consumer'у — забыли volume-mount
|
||
2. `/run/cuframes` смонтирован, но publisher ещё не успел создать socket — увеличить `connect_timeout_ms`
|
||
3. Publisher запущен, socket есть, но **permission denied** — см. ниже
|
||
|
||
### Permission denied на socket
|
||
|
||
**Симптом**: socket виден через `ls -la /run/cuframes/`, owner `root`. Consumer process — non-root user → не может `connect()`.
|
||
|
||
**Fix**:
|
||
- Запустить consumer как root: `user: root` в compose
|
||
- Либо изменить permissions socket после создания (publisher delegation) — TBD в v0.2
|
||
|
||
---
|
||
|
||
## Frigate-specific
|
||
|
||
### `s6-overlay-suexec: fatal: can only run as pid 1`
|
||
|
||
**Симптом**: container Frigate'а в restart loop, в logs только эта ошибка.
|
||
|
||
**Причина**: `pid: container:<publisher>` сделал Frigate not-PID-1 в shared namespace. s6-overlay v3 strictly требует PID 1 для proper signal handling/zombie reaping.
|
||
|
||
**Fix**: убрать `pid: container:` для Frigate. Только `ipc: container:` shared.
|
||
|
||
**Trade-off**: без shared pid некоторые edge cases CUDA IPC ломаются (см. [соответствующую секцию](#cudaipcopeneventhandle-invalid-device-context)). Frigate **на практике** работает потому что подключается до того как CUDA driver проверяет peer (race window race), но если publisher restart'нётся посередине — Frigate'у не удастся пере-подключиться без перезапуска.
|
||
|
||
**Real fix** (planned v0.2): encoded packet sharing — Frigate detect получает кадры через decoded path (work-around), record получает encoded через socket-based protocol который **не** требует cudaIpcOpenEventHandle.
|
||
|
||
### `No such filter: 'scale_cuda'`
|
||
|
||
**Симптом**: Frigate ffmpeg subprocess падает с этой ошибкой в `AVFilterGraph`.
|
||
|
||
**Причина**: наш patched FFmpeg собран без `--enable-cuda-llvm` (см. [stdbit.h grабля](#stdbith-no-such-file-при---enable-cuda-llvm)). Без cuda-llvm в FFmpeg нет CUDA filters (scale_cuda, overlay_cuda).
|
||
|
||
**Fix**: в Frigate config.yml явно отключи hwaccel cuda:
|
||
```yaml
|
||
ffmpeg:
|
||
hwaccel_args: [] # CPU scale вместо scale_cuda
|
||
```
|
||
|
||
Cost: 5-10% CPU per FHD25 камера. **Real fix** (v0.2): publisher-side resize в cuframes сам.
|
||
|
||
### Missing dynamic .so после ffmpeg replace
|
||
|
||
**Симптом**: после `docker cp` patched ffmpeg в Frigate container — `ldd ffmpeg`
|
||
показывает `libharfbuzz.so.0 => not found`, `libfribidi.so.0 => not found`, …
|
||
~20 missing .so.
|
||
|
||
**Причина**: Frigate's bundled ffmpeg **статически слинкован** (NickM-27/FFmpeg-Builds
|
||
делает full static build). Все 30+ deps встроены в один binary. Frigate runtime
|
||
image **не имеет** этих .so packages installed (ему не надо — bundled ffmpeg
|
||
self-contained).
|
||
|
||
Наш custom ffmpeg — **dynamic linked** (apt deps). Нужны .so на target.
|
||
|
||
**Fix**: либо
|
||
- `apt install` missing libs в Frigate (additive image modification):
|
||
```bash
|
||
apt install libharfbuzz0b libfribidi0 librist4 libsrt1.5-openssl libssh-4 \
|
||
libvpx7 libwebpmux3 libwebp7 libdav1d6 libaom3 libmp3lame0 \
|
||
libsvtav1enc1 libtheora0 libvorbis0a libvorbisenc2 \
|
||
libx264-164 libx265-199 libopus0
|
||
```
|
||
- Либо строить наш ffmpeg static (sources from NickM-27 pipeline) — complex
|
||
(см. [zlib download / GMP compiler граблю](#zlib-download-failed-в-crosstool-ng))
|
||
|
||
Best practice: создать `Dockerfile.frigate` overlay поверх Frigate image,
|
||
который добавляет deps и копирует ffmpeg. Запечь в image, не in-place patch.
|
||
|
||
---
|
||
|
||
## Build / FFmpeg patch
|
||
|
||
### `libcuframes not found` при configure
|
||
|
||
**Симптом**: FFmpeg configure (с `--enable-libcuframes`) fails с этой ошибкой
|
||
из `enabled libcuframes && require libcuframes ...`. config.log показывает
|
||
`fatal error: cuframes/cuframes.h: No such file or directory`.
|
||
|
||
**Причины**:
|
||
|
||
1. **CMake install rules отсутствовали** в libcuframes (early commits до 601806a).
|
||
`cmake --install` создавал пустой prefix. Fix: обновить cuframes до ≥ 601806a.
|
||
|
||
2. **Wrong HINTS в find_library**: твой проект ищет в `${CUFRAMES_ROOT}/build/...`
|
||
но install layout кладёт в `${CUFRAMES_ROOT}/lib`. Добавь оба пути в HINTS.
|
||
|
||
3. **`rm -f libcuframes.so*`** удалил .so но **.a** file называется
|
||
`libcuframes_static.a` (не `libcuframes.a`) → linker не находит `-lcuframes`.
|
||
Fix: либо не удаляй .so, либо переименуй .a при install.
|
||
|
||
### `ffbuild/library.mak: No such file`
|
||
|
||
**Симптом**: configure FFmpeg success, но `make` падает сразу:
|
||
`Makefile:123: ffbuild/library.mak: No such file or directory`.
|
||
|
||
**Причина**: вы сделали ваш fork FFmpeg через snapshot (не git clone), и **случайно
|
||
исключили `ffbuild/`** в rsync. Это **source files** FFmpeg, не build artifacts.
|
||
|
||
**Fix**: убедись что `ffbuild/` есть в твоём FFmpeg checkout (`ls ffbuild/library.mak`).
|
||
Если делаешь snapshot через rsync — не используй `--exclude=ffbuild`.
|
||
|
||
### `could not find a working compiler` (GMP)
|
||
|
||
**Симптом**: crosstool-NG build падает на `Installing GMP for host` с
|
||
`configure: error: could not find a working compiler`. config.log показывает
|
||
`no, long long reliability test 1`.
|
||
|
||
**Причина**: GMP 6.2.1 имеет known issue с GCC 11+ (Ubuntu 22.04 default).
|
||
Проверка long-long reliability fail'ит false-positive.
|
||
|
||
**Fix**: pin GMP к 6.3.0 в `ct-ng-config`:
|
||
```
|
||
CT_GMP_V_6_3=y
|
||
# CT_GMP_V_6_2 is not set
|
||
CT_GMP_VERSION="6.3.0"
|
||
```
|
||
|
||
И убедись что crosstool-NG version (commit) поддерживает 6.3.0 (≥ master 2024-09).
|
||
|
||
### `zlib: download failed` в crosstool-NG
|
||
|
||
**Симптом**: crosstool-NG step `Retrieving 'zlib-1.2.12'` fail'ит.
|
||
|
||
**Причина**: zlib.net убрали старые versions с дефолтного location — теперь они
|
||
только в `/fossils/` subdirectory. Crosstool-NG hardcoded URL не работает.
|
||
|
||
**Fix**: pre-fetch tarball + положить в local cache:
|
||
```bash
|
||
wget https://zlib.net/fossils/zlib-1.2.12.tar.gz -O preload/zlib-1.2.12.tar.gz
|
||
```
|
||
|
||
В Dockerfile перед `ct-ng build`:
|
||
```dockerfile
|
||
COPY preload/*.tar.gz /root/src/
|
||
```
|
||
|
||
`CT_LOCAL_TARBALLS_DIR=${HOME}/src` — crosstool-NG найдёт в cache и не пойдёт
|
||
download.
|
||
|
||
### `stdbit.h: No such file` при `--enable-cuda-llvm`
|
||
|
||
**Симптом**: FFmpeg configure с `--enable-cuda-llvm` fail'ит:
|
||
`fatal error: stdbit.h: No such file or directory`. ERROR: cuda_llvm requested
|
||
but not found.
|
||
|
||
**Причина**: `stdbit.h` — C23 standard header. Доступен в glibc ≥ 2.38.
|
||
|
||
- Ubuntu 22.04 = glibc 2.35 — **нет**
|
||
- Debian 12 = glibc 2.36 — **нет**
|
||
- Ubuntu 24.04 = glibc 2.39 — есть
|
||
- Debian 13 (trixie) = glibc 2.38+ — есть
|
||
|
||
**Fix options**:
|
||
1. Build на newer base (Ubuntu 24.04+). Но runtime target (Frigate Debian 12)
|
||
не запустит binary с glibc-2.38 symbols (backwards-incompatible).
|
||
2. Убрать `--enable-cuda-llvm`. Потеря: CUDA filters (`scale_cuda`, `overlay_cuda`,
|
||
`hwupload_cuda`). Decode/encode через NVDEC/NVENC всё равно работают.
|
||
3. Дождаться когда Frigate base обновится до newer Debian — вне твоего контроля.
|
||
|
||
**На практике**: убираем cuda-llvm, в Frigate config `hwaccel_args: []`.
|
||
См. [scale_cuda секцию](#no-such-filter-scale_cuda).
|
||
|
||
---
|
||
|
||
## Docker / IPC
|
||
|
||
### Cross-container CUDA IPC: ipc + pid namespace share
|
||
|
||
| Что нужно | Compose option |
|
||
|---|---|
|
||
| /dev/shm shared (для cuframes header + SHM ring) | `ipc: container:<publisher>` (либо `ipc: shareable` у publisher + same у consumer) |
|
||
| /proc visibility (для CUDA IPC peer validation) | `pid: container:<publisher>` |
|
||
| `/run/cuframes/*.sock` доступен | volume mount: `cuframes_sock:/run/cuframes:ro` |
|
||
| GPU access | `runtime: nvidia` |
|
||
| Socket permissions | `user: root` (либо chmod socket в publisher) |
|
||
|
||
**Все 5** должны быть выполнены. Один пропуск — fail при subscriber_create или
|
||
cudaIpcOpenEventHandle.
|
||
|
||
### Buildx container driver не видит host images
|
||
|
||
**Симптом**: при использовании custom buildx builder (`docker buildx create
|
||
--driver docker-container ...`) с `FROM local-image:tag` — error `failed to
|
||
authorize: 403 Forbidden` (buildkit пытается pull с registry).
|
||
|
||
**Причина**: container driver buildx изолирован, не имеет доступа к host's
|
||
local docker daemon images. Pull через registry.
|
||
|
||
**Fix**: либо
|
||
- Не использовать custom builder — `docker buildx use default` (использует host
|
||
daemon). Минус: теряем `--cache-to/--cache-from type=local`.
|
||
- Либо push local image в **registry** (local или gitea), и buildx pull'ит оттуда.
|
||
|
||
---
|
||
|
||
## Networking / RTSP
|
||
|
||
### RTSP/RTP UDP не доходит до клиента (docker NAT)
|
||
|
||
**Симптом**: RTSP server в docker контейнере с `ports: "554:8555"`. Клиент (TV, VLC)
|
||
делает RTSP SETUP successfully (TCP control работает), но video frames не приходят.
|
||
|
||
**Причина**: RTP идёт **UDP**, sourced из docker network namespace. SNAT MASQUERADE
|
||
для outbound работает, но RTP destination port (которое клиент опубликовал в SETUP)
|
||
**не маппится обратно** через docker bridge — клиент видит UDP packets от чужого
|
||
source IP (docker network 172.x), не от 192.168.88.23 как expected.
|
||
|
||
**Fix**: `network_mode: host` для RTSP-server контейнера. Тогда server listens
|
||
**напрямую** на host interfaces, RTP packets идут без NAT.
|
||
|
||
Trade-offs:
|
||
- Все ports app'а listen на host network (нет port mapping). Проверь port collisions.
|
||
- DB env vars (postgres:5432 в docker network DNS) надо менять на host paths
|
||
(`localhost:5433` если postgres exposed на host port 5433).
|
||
|
||
### `Nonmatching transport in server reply`
|
||
|
||
**Симптом**: `ffprobe -rtsp_transport tcp -i rtsp://...` falls с этим сообщением.
|
||
|
||
**Причина**: RTSP server возвращает SDP с UDP-only transport. Client ожидает TCP
|
||
interleaved.
|
||
|
||
**Fix**: использовать UDP transport: `-rtsp_transport udp` (либо default behavior).
|
||
Если TV не поддерживает UDP — нужен RTSP server который умеет RTP-over-TCP
|
||
interleaved (cctv-processor v0.1 не умеет).
|
||
|
||
---
|
||
|
||
## Gitea Actions / CI
|
||
|
||
### `node: executable file not found`
|
||
|
||
**Симптом**: первый JS action (например `actions/checkout@v4`) fail'ит:
|
||
`OCI runtime exec failed: exec: "node": executable file not found in $PATH`.
|
||
|
||
**Причина**: гитея act_runner запускает JS actions через `node`, но твой
|
||
custom container (например `nvidia/cuda:...`) не имеет node installed.
|
||
|
||
**Fix**: pre-install node в первом `run:` step (до actions/checkout):
|
||
```yaml
|
||
steps:
|
||
- name: Bootstrap node
|
||
run: apt-get update && apt-get install -y nodejs git ca-certificates
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
```
|
||
|
||
Либо использовать container с node pre-installed (`docker.gitea.com/runner-images:ubuntu-22.04`).
|
||
|
||
### `SyntaxError: Unexpected token '{'` (Node 12)
|
||
|
||
**Симптом**: после `apt install nodejs` в Ubuntu 22.04 — actions/checkout@v4 fail'ит:
|
||
`SyntaxError: Unexpected token '{' at static {...}`.
|
||
|
||
**Причина**: Ubuntu 22.04 apt'овский `nodejs` = Node **12**. `actions/checkout@v4`
|
||
скомпилирован для Node 20+ (static class blocks — ES2022).
|
||
|
||
**Fix**: install Node 20 from NodeSource:
|
||
```bash
|
||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||
apt-get install -y nodejs
|
||
```
|
||
|
||
В Ubuntu 24.04 apt уже даёт Node 20 — там goes автоматически.
|