Работа с Entrosity Sphere
Entrosity Sphere работи до Entrosity Hub, Axis и Edge на същия хост. Той
е по избор за всеки хост: профилът sphere на compose съдържа услугите
му, а скриптовете за разгръщане ги стартират само когато deploy/.env
съдържа SPHERE_ENABLED=true
(Включване на Sphere на хост).
| Част | Къде |
|---|---|
Уеб приложение (entrosity-sphere.frontend) | https://hub.entrosity.com/sphere/, обслужвано от Caddy от уеб образа |
API (entrosity-sphere.backend, образ ghcr.io/entrosity/sphere-backend) | https://hub.entrosity.com/sphere/api/…; Caddy премахва /sphere, така че бекендът обслужва /api/v1 (браузъри), /api/connector/v1 (конектори) и /api/releases/v1 (инсталатори на конектора: качване от CI, връзки за изтегляне с изтичащ срок) |
| Медиен сървър (MediaMTX) | Конекторите публикуват на rtsps://media.entrosity.com:8322 (отделно DNS-only име на същия сървър, по-долу); браузърите договарят през https://hub.entrosity.com/sphere/media/… (WHEP) и получават медията на порт 8189 на публичния адрес на сървъра |
| База данни | Собствена база данни в PostgreSQL (sphere), мигрирана от бекенда |
| Влизане | Entrosity Hub, продукт sphere |
Услуги
deploy/docker-compose.prod.yml на entrosity-infra, профил sphere:
| Услуга | Образ | Какво прави |
|---|---|---|
sphere-db-init | postgres:18-alpine | Създава базата данни sphere (собственик rmm) веднъж. |
sphere-migrate | sphere-backend | Изпълнява migrate up като собственик и разрешава входа sphere_app със SPHERE_APP_DATABASE_PASSWORD. |
sphere | sphere-backend | sphere-server serve, една инстанция: конекторите държат WebSocket към нея, а уеб приложението – поток от събития. Публичен API на :8080 зад Caddy; hook-ът на медийния сървър на вътрешния слушател :8084 (Caddy никога не го маршрутизира); метрики на :9094. Проверка на здравето: sphere-server healthcheck. Ограничение на паметта SPHERE_MEMORY (512m), GOMEMLIMIT от SPHERE_GOMEMLIMIT (400MiB). |
sphere-media | bluenviron/mediamtx, закрепен по таг и digest | Медийният сървър (по-долу). Публикува 8189/udp и 8189/tcp на хоста. Ограничение на паметта SPHERE_MEDIA_MEMORY (1g). Стартира, след като sphere е здрав. |
Услугата web (Caddy) обслужва и Sphere:
| Път или порт | Отива към |
|---|---|
/sphere/ | Уеб приложението (от образа sphere-frontend, вграден в уеб образа) |
/sphere/api/* | sphere:8080, с премахнат /sphere |
/sphere/media/* | sphere-media:8889 (WHEP), с премахнат /sphere/media; адресите на сесиите на медийния сървър се пренаписват обратно под /sphere/media |
:8322 (TCP) | Маршрут на ниво 4: Caddy терминира TLS със сертификата на SPHERE_MEDIA_DOMAIN и препраща чист RTSP към sphere-media:8554 |
SPHERE_MEDIA_DOMAIN (сайт) | Съществува само за да може Caddy да получи сертификата на медийния хост (HTTP-01 на порт 80); отговаря с 404. Без Sphere сайтът е заместителят http://media.invalid. |
Изпълнимият файл на бекенда е sphere-server:
sphere-server serve run the HTTP API and job workers (default)
sphere-server migrate [cmd] database migrations: up | down [N] | version | force N
(up also sets the sphere_app login password when
SPHERE_APP_DATABASE_PASSWORD is set)
sphere-server healthcheck exit 0 when this host's server is ready (/readyz), for
container health checks
sphere-server version print the version
В Hub продуктът sphere (роли tenant_admin, operator, viewer) се
регистрира от миграция 0006 на Hub като изключен и в бета версия
и се включва от миграция 0007 (Въвеждане). Hub трябва да знае
токена на Sphere: PLATFORM_PRODUCT_TOKENS съдържа sphere:<token> със
същата стойност като SPHERE_PLATFORM_TOKEN. В продукция и двете идват
от PLATFORM_PRODUCT_TOKEN_SPHERE в deploy/.env.
Справочник на конфигурацията
Бекендът се конфигурира само чрез променливи на средата SPHERE_*
(entrosity-sphere.backend/internal/config). Невалидни стойности спират
стартирането със списък на всички проблеми. Разделът RETENTION приема
едно или две долни тирета: SPHERE_RETENTION_ALARM_DAYS =
SPHERE_RETENTION__ALARM_DAYS.
Сървър
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_ENV | dev | dev, test или prod. prod отказва примерните тайни за разработка и пише журнала в JSON. |
SPHERE_PUBLIC_URL | http://localhost:8083 | Публичният адрес на Sphere, включително представката /sphere, която проксито премахва (https://hub.entrosity.com/sphere). Конекторите получават <SPHERE_PUBLIC_URL>/api/connector/v1/ws, а командите за инсталиране, показвани с нови токени за регистриране, го използват като SERVER_URL. |
SPHERE_HTTP_ADDR | :8083 | Слушател на API (продукция: :8080). |
SPHERE_INTERNAL_ADDR | :8084 | Вътрешен слушател за hook-а за удостоверяване на медийния сървър (POST /media/auth). Никога не го маршрутизирайте публично. |
SPHERE_METRICS_ADDR | :9094 | Вътрешен слушател за Prometheus /metrics. Никога не го излагайте публично; празно го изключва. |
SPHERE_LOG_LEVEL | info | debug, info, warn или error. |
SPHERE_CORS_ORIGINS | http://localhost:5177 | Разрешени произходи (origins) на браузъри, разделени със запетая, без заместващи символи и пътища (продукция: https://hub.entrosity.com). |
SPHERE_TRUSTED_PROXIES | няма | CIDR или IP адреси, на които е разрешено да задават X-Forwarded-For (продукция: мрежата на compose 172.30.0.0/24). |
SPHERE_API_RATE_PER_SECOND, SPHERE_API_RATE_BURST | 20, 60 | Ограничение на заявките към уеб API за IP адрес на клиент (офис зад един NAT адрес го споделя). |
SPHERE_ENROLL_RATE_PER_MINUTE | 60 | Регистрирания на конектори за IP адрес на клиент. |
SPHERE_CONNECTOR_DOWNLOAD_URL | няма | Откъде може да се изтегли MSI на конектора; показва се с новите токени за регистриране, докато няма съхранено издание на конектора (Издания на конектора). |
База данни
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_DATABASE_URL | няма (задължителна) | URL за връзка. Продукцията се свързва като sphere_app. |
SPHERE_DATABASE_ROLE | sphere_app | Ролята, към която пулът превключва след свързване (SET ROLE), така че защитата на ниво ред важи дори при връзка като собственик. Празно, когато входът вече е ролята на приложението и не може да превключва. |
SPHERE_DATABASE_MAX_CONNS | 20 | Размер на пула. |
SPHERE_DATABASE_STATEMENT_TIMEOUT | 30s | Горна граница за всяка заявка. |
SPHERE_APP_DATABASE_PASSWORD | няма | Чете се от migrate up: разрешава входа sphere_app с тази парола. |
Тайни
| Променлива | Значение |
|---|---|
SPHERE_JWT_SECRET | Задължителна. Поне 32 байта, сурови или base64. Подписва едноминутните токени за потока с обновления на живо (POST /auth/sse-token) и петминутните медийни токени, с които браузърите възпроизвеждат видео. Токените за достъп на потребителите идват от Hub. |
SPHERE_JWT_SECRET_OLD | Предишната тайна по време на смяна (все още се проверява). |
SPHERE_CREDENTIALS_KEY | Задължителна. Точно 32 байта, base64: криптира паролите на видеорекордерите в базата данни (AES-256-GCM; ID на видеорекордера е свързан с шифрования текст, така че шифрован текст, копиран към друг видеорекордер, не се декриптира). |
SPHERE_CREDENTIALS_KEY_OLD | Предишният ключ по време на смяна: той още декриптира; новите и променените пароли използват текущия ключ. |
При SPHERE_ENV=prod стойностите, съдържащи dev-only (примерите за
разработка), се отказват.
Без SPHERE_CREDENTIALS_KEY (или с друг ключ) нито една парола на
видеорекордер не може да бъде декриптирана: конекторите не могат да влязат в
нито един видеорекордер, докато всички пароли не бъдат въведени отново. Пазете
копие на deploy/.env заедно с резервните копия.
Влизане чрез Entrosity Hub
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_PLATFORM_URL | няма (задължителна) | Публичният произход на Hub (https://hub.entrosity.com): издателят на токените за продукт и мястото, където браузърите влизат. |
SPHERE_PLATFORM_INTERNAL_URL | няма (задължителна) | Вътрешният API на Hub, достъпван директно, а не през проксито (compose: http://platform:8081): ключове за подписване и моментната снимка на достъпа. |
SPHERE_PLATFORM_TOKEN | няма (задължителна) | Bearer токенът на Sphere за вътрешния API на Hub, поне 32 знака; sphere:<token> в PLATFORM_PRODUCT_TOKENS на Hub. |
SPHERE_PLATFORM_SYNC_INTERVAL | 30s | Колко често Sphere изтегля потребителите, организациите и ролите от Hub (поне 1s). |
Медия и потоци
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_MEDIA_PUBLISH_URL | rtsp://localhost:8554 | Къде публикуват конекторите: rtsp(s)://host:port, без път (продукция: rtsps://media.entrosity.com:8322). Изпраща се на конектора с всяко стартиране на поток. |
SPHERE_MEDIA_WHEP_URL | /sphere/media | Основата, от която възпроизвеждат браузърите, <base>/<path>/whep: път в произхода на Sphere или абсолютен URL, без наклонена черта накрая. |
SPHERE_MAX_STREAMS_PER_CONNECTOR | 64 | Едновременно отворени потоци (на живо и записи) на конектор: капацитетът за качване на обекта. 64 запълват мрежа 8×8. |
SPHERE_MAX_MAIN_STREAMS_PER_NVR | 4 | Потоци на живо с пълна резолюция на видеорекордер. |
SPHERE_MAX_PLAYBACKS_PER_NVR | 4 | Възпроизвеждания на записи на видеорекордер (видеорекордерите обслужват малко едновременно). |
SPHERE_LIVE_IDLE_GRACE | 5m | Колко дълго продължава подпоток на живо, който никой не гледа, така че връщането към камерата пропуска стартирането във видеорекордера. Продължителност в Go, поне 10s (досега фиксирано 30 секунди). |
SPHERE_LIVE_IDLE_GRACE_MAIN | 2m | Същото за основните потоци. Поне 10s. |
Неизползваните потоци струват от капацитета за качване на обекта, докато
вървят, и се броят към ограниченията. При достигнато ограничение
(SPHERE_MAX_STREAMS_PER_CONNECTOR или SPHERE_MAX_MAIN_STREAMS_PER_NVR)
неизползваният поток на живо, който не е гледан най-дълго, се спира, за
да освободи място; потоци със зрители никога не се спират, а
възпроизвежданията на записи никога не остават неизползвани (спират,
когато зрителят им излезе). Само когато никой неизползван поток не може
да освободи място, заявката на зрителя връща 409 stream_limit.
Конекторът има собствено ограничение (SPHERE_CONNECTOR_MAX_STREAMS, по подразбиране 64;
Конектор на Sphere).
Обновявания на конектора
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_RELEASE_SIGNING_KEY | няма | Подписва изданията на конектора: ключ Ed25519, base64 на 32-байтовото начално число (seed) или на 64-байтовия частен ключ. Публичната му половина е RELEASE_PUBLIC_KEY, с който се компилират конекторите. Празна стойност изключва качването и самообновяването (качванията връщат 503 releases_disabled). Невалидна стойност спира сървъра. |
SPHERE_RELEASE_TOKEN | няма | Bearer токенът на CI за качване на версии на конектора (POST /api/releases/v1/connector), поне 32 знака. Празна стойност: всяко качване връща 401. |
SPHERE_CONNECTOR_UPDATE_CHANNEL | stable | До какво се обновяват конекторите (и какво предлага Изтегляне на конектора): stable (само издания с етикет) или dev (версии за разработка и издания с етикет). Продукционният compose файл задава dev, докато Sphere е в бета. |
Вижте Издания на конектора.
Срокове за съхранение
| Променлива | По подразбиране | Значение |
|---|---|---|
SPHERE_RETENTION_ALARM_DAYS | 365 | Журнал с аларми. |
SPHERE_RETENTION_JOB_DAYS | 90 | Приключили задачи на конекторите. Тенантите могат да го заменят (7–730). |
SPHERE_RETENTION_AUDIT_DAYS | 365 | Одитен журнал. Тенантите могат да го заменят (30–3650). |
0 или незададена стойност запазва стойността по подразбиране.
Настройки на хоста
В продукция файлът на compose фиксира повечето от горните
(SPHERE_PUBLIC_URL=https://${PLATFORM_DOMAIN}/sphere,
SPHERE_MEDIA_PUBLISH_URL=rtsps://${SPHERE_MEDIA_DOMAIN}:8322, слушателите,
доверените проксита). deploy/.env (deploy/.env.prod.example ги
изброява) задава останалото:
| Променлива | Значение |
|---|---|
SPHERE_ENABLED | true пуска профила sphere. По подразбиране false. |
SPHERE_APP_DATABASE_PASSWORD | Паролата на входа sphere_app. Задължителна, когато е включен. |
SPHERE_JWT_SECRET, SPHERE_JWT_SECRET_OLD | Както по-горе. Първата е задължителна, когато е включен. |
SPHERE_CREDENTIALS_KEY, SPHERE_CREDENTIALS_KEY_OLD | Както по-горе. Първият е задължителен, когато е включен. |
PLATFORM_PRODUCT_TOKEN_SPHERE | Токенът на Sphere в Hub: става SPHERE_PLATFORM_TOKEN и записът sphere: в PLATFORM_PRODUCT_TOKENS на Hub. Задължителен, когато е включен. |
SPHERE_MEDIA_DOMAIN | Името на медийния хост, към което конекторите публикуват видео (media.entrosity.com): A запис, сочещ директно към този сървър, само DNS (без прокси). Използва се за SPHERE_MEDIA_PUBLISH_URL и се подава на услугата web, която получава сертификата му. Задължителна, когато е включен. |
SPHERE_MEDIA_PUBLIC_IP | Публичният IP адрес на хоста, който се обявява на браузърите като адрес на медията (webrtcAdditionalHosts). Задължителен, когато е включен. |
SPHERE_MAX_STREAMS_PER_CONNECTOR, SPHERE_MAX_MAIN_STREAMS_PER_NVR, SPHERE_MAX_PLAYBACKS_PER_NVR | Ограничения на потоците (64, 4, 4). |
SPHERE_LIVE_IDLE_GRACE, SPHERE_LIVE_IDLE_GRACE_MAIN | Време, през което неизползваните потоци продължават (5m, 2m). |
SPHERE_RELEASE_SIGNING_KEY, SPHERE_RELEASE_TOKEN | Самообновяване на конекторите, както по-горе. По избор: празни стойности го изключват (Включване на самообновяването на конекторите). |
SPHERE_CONNECTOR_UPDATE_CHANNEL | Както по-горе; на хоста по подразбиране dev, докато Sphere е в бета. |
SPHERE_CONNECTOR_DOWNLOAD_URL, SPHERE_LOG_LEVEL | Както по-горе. |
SPHERE_BACKEND_IMAGE | По подразбиране ghcr.io/entrosity/sphere-backend. |
SPHERE_MEMORY, SPHERE_GOMEMLIMIT, SPHERE_MEDIA_MEMORY | Ограничения на паметта: 512m, 400MiB, 1g. |
Генериране на тайните
openssl rand -base64 32 # SPHERE_JWT_SECRET, SPHERE_CREDENTIALS_KEY (exactly 32 bytes)
openssl rand -hex 32 # SPHERE_APP_DATABASE_PASSWORD, PLATFORM_PRODUCT_TOKEN_SPHERE, SPHERE_RELEASE_TOKEN
Ключът за подписване на изданията е двойка ключове: Включване на самообновяването на конекторите.
Паролата за базата данни попада в URL за връзка, затова използвайте
стойност без /, + и = (hex). Токенът за продукта трябва да е поне 32
знака.
Портове и защитна стена
Освен 443, Sphere има нужда от тези портове, отворени за входящи връзки в защитната стена на хоста:
| Порт | Услуга | За |
|---|---|---|
| 80/tcp | web (Caddy) | Трябва да достига директно до сървъра на SPHERE_MEDIA_DOMAIN: Caddy получава сертификата на медийния хост с проверката HTTP-01. |
| 8322/tcp | web (Caddy) | Конекторите публикуват видео към SPHERE_MEDIA_DOMAIN: RTSP през TLS, терминиран от Caddy със сертификата на това име (конекторът го изпраща като SNI). |
| 8189/udp и 8189/tcp | sphere-media | WebRTC медия към браузърите (за предпочитане UDP, TCP, когато UDP е блокиран). |
Браузърите договарят WebRTC през /sphere/media на 443 и след това
получават медията на 8189 на адреса SPHERE_MEDIA_PUBLIC_IP. Няма TURN
сървър: зрител, чиято мрежа блокира изходящ 8189 (UDP и TCP), не вижда
видео.
Зад Cloudflare (или друго прокси)
hub.entrosity.com е зад проксито на Cloudflare, което препраща HTTP(S)
на 443, но не и чист TCP на 8322, нито UDP или TCP на 8189. Затова:
- Конекторите публикуват видео към отделно име на хост, само DNS,
SPHERE_MEDIA_DOMAIN(media.entrosity.com): A запис, сочещ към сървъра, с изключено прокси (сивият облак на Cloudflare), както хоста за файлове. Caddy получава сертификата му през порт 80 и го представя на 8322. - Контролната връзка на конектора (WebSocket, задачи, аларми) остава на
hub.entrosity.com:443, както и WebRTC договарянето на браузърите (/sphere/media, WHEP), което проксито препраща като всяка HTTPS заявка. - WebRTC медията минава директно от
SPHERE_MEDIA_PUBLIC_IPна сървъра на 8189 към браузъра, никога през проксито.
Затова публичният IP адрес на сървъра става видим (чрез DNS записа на медийния хост и WebRTC кандидатите), както вече е видим чрез хоста за файлове.
Медийният сървър
sphere-media изпълнява MediaMTX с deploy/mediamtx.yml:
- Всяко действие се решава от Sphere:
authMethod: httpизпраща всяко публикуване и гледане къмhttp://sphere:8084/media/auth. Hook-ът разрешава:- публикуване по RTSP с ID на конектора като потребител и ключа му
като парола и само под представката на собствения му тенант
t/<tenant id>/; - гледане по WebRTC (или HLS) с медиен токен, в който е посочен
точно този път (като bearer токен,
?jwt=или парола в basic идентификационни данни); - нищо друго (API, метриките и pprof на MediaMTX са изключени от hook-а и остават в мрежата на compose или са изключени).
- публикуване по RTSP с ID на конектора като потребител и ключа му
като парола и само под представката на собствения му тенант
- Пътища: съществуват само
t/<tenant>/live/<camera>/<main|sub>иt/<tenant>/pb/<session>. - RTSP на :8554, само TCP (Caddy препраща байтове, не UDP), без
криптиране (TLS свършва в Caddy), basic удостоверяване. Конектор, който
рестартира поток, поема мястото на предишната си сесия
(
overridePublisher). Нищо не се записва. - WebRTC на :8889 (WHEP, зад Caddy) с медията на :8189 UDP и TCP;
обявява се само
SPHERE_MEDIA_PUBLIC_IP(webrtcIPsFromInterfaces: false). - RTMP, SRT, MoQ, HLS, сървърът за възпроизвеждане и метриките са изключени.
Обновяване на MediaMTX
Образът е закрепен по таг и digest
(bluenviron/mediamtx:1.21.1@sha256:…) и в
deploy/docker-compose.prod.yml, и в deploy/docker-compose.yml за
разработка. За обновяване:
- Прочетете бележките към изданията между двете версии.
- Проверете всеки ключ на
deploy/mediamtx.ymlспрямо справочната конфигурация на новата версия, особеноauthMethod,authHTTPAddress,authHTTPExclude,rtspTransports,rtspEncryption,rtspAuthMethods,webrtcAdditionalHosts,webrtcIPsFromInterfaces,webrtcLocalUDPAddress,webrtcLocalTCPAddress,webrtcICEServers2,overridePublisherи протоколите, които трябва да останат изключени. - Сменете тага и digest-а в двата файла на compose.
- Изпробвайте локално с конектор (симулаторът
е достатъчен): поток се публикува през TLS на 8322 на медийния хост, възпроизвежда се в
браузъра през
/sphere/media, а гледане без токен или с токена на друг път се отказва.
Включване на Sphere на хост
- Създайте A записа на медийния хост само DNS
(
media.entrosity.com→ публичният IP на сървъра, без прокси) и изчакайте да сочи към сървъра: Caddy има нужда от него, за да получи сертификата. - Генерирайте тайните и ги задайте заедно с
PLATFORM_PRODUCT_TOKEN_SPHERE,SPHERE_MEDIA_DOMAINиSPHERE_MEDIA_PUBLIC_IPвdeploy/.env. - Отворете 8322/tcp и 8189/udp+tcp в защитната стена на хоста (и 80/tcp към медийния хост).
- Задайте
SPHERE_ENABLED=true. - Разгърнете (следващото изпълнение на
deployилиdeploy/scripts/upgrade.sh).
При SPHERE_ENABLED=true deploy/scripts/lib.sh добавя
--profile sphere към всяка команда на compose и отказва да работи,
докато SPHERE_APP_DATABASE_PASSWORD, SPHERE_JWT_SECRET,
SPHERE_CREDENTIALS_KEY, PLATFORM_PRODUCT_TOKEN_SPHERE,
SPHERE_MEDIA_DOMAIN или SPHERE_MEDIA_PUBLIC_IP е празна. След това upgrade.sh изтегля образите
на Sphere и след Hub изпълнява sphere-migrate, рестартира sphere (и
изчаква да стане здрав) и след това sphere-media. Финалната проверка на
работния поток deploy чака и /sphere/api/v1/healthz на хостовете със
SPHERE_ENABLED=true.
Въвеждане
Sphere достига до потребителите в четири стъпки:
- Регистриран, изключен. Миграция 0006 на Hub регистрира продукта
sphereизключен и в бета версия: никой не го вижда. - Разгърнат. Образите
sphere-backendиsphere-frontendс тагmainсъществуват, DNS записът на медийния хост сочи към сървъра, хостът е настроен както по-горе съсSPHERE_ENABLED=trueи разгръщането е направено. - Включен, в бета версия. Миграция 0007 на Hub включва продукта. Той остава в бета версия: само администраторите на платформата го виждат и отварят и могат да го включват за организации.
- Пуснат. Администратор на платформата избира Release to organizations (Продукти в бета версия).
Работният поток deploy изтегля sphere-backend:main и изгражда уеб
образа със sphere-frontend:main при всяко изпълнение, независимо дали
хостът включва Sphere. Публикувайте промяната в entrosity-infra, която
добавя Sphere, само след като и двата образа са публикувани, иначе всяко
разгръщане се проваля (Непрекъснато разгръщане).
Миграция 0007 трябва да влезе в издание на Hub, разгърнато след стъпка 2:
преди това списъкът с продукти би водил към Sphere, който не отговаря.
Издания на конектора
Sphere пази инсталаторите на конектора и ги разпространява: CI качва всяка версия, Sphere я подписва, на конекторите, които могат да се обновяват сами, се предлага най-новата, а администраторите на тенанта я изтеглят от Изтегляне на конектора (Конектори → Обновявания).
Включване на самообновяването на конекторите
-
Генерирайте веднъж двойката ключове Ed25519 (OpenSSL 3):
openssl genpkey -algorithm ed25519 -out sphere-release.pemopenssl pkey -in sphere-release.pem -outform DER | tail -c 32 | base64 # SPHERE_RELEASE_SIGNING_KEY (the seed)openssl pkey -in sphere-release.pem -pubout -outform DER | tail -c 32 | base64 # RELEASE_PUBLIC_KEYopenssl rand -hex 32 # SPHERE_RELEASE_TOKENПазете началното число (seed) толкова тайно, колкото и другите ключове, и след това изтрийте
sphere-release.pem. -
В
deploy/.envна хоста задайтеSPHERE_RELEASE_SIGNING_KEY(началното число) иSPHERE_RELEASE_TOKENи по желаниеSPHERE_CONNECTOR_UPDATE_CHANNEL(на хоста по подразбиранеdev). -
В хранилището
entrosity-sphere-connectorзадайте тайнитеRELEASE_PUBLIC_KEY(публичният ключ, компилиран в конектора) иSPHERE_RELEASE_TOKEN(същият токен), както и променливатаRELEASE_PUBLISH_ENABLED=true.SPHERE_RELEASE_API(променлива) сменя адреса, по подразбиранеhttps://hub.entrosity.com/sphere/api/releases/v1(Работни потоци на CI). -
Разгърнете отново (следващото изпълнение на
deployилиdeploy/scripts/upgrade.sh). Следващата версия на конектора се качва и предлага. -
Конекторите, инсталирани преди това, са компилирани без публичния ключ и не могат да се обновяват сами: инсталирайте новата версия на всеки от тях веднъж, от Изтегляне на конектора (Конектори → Обновявания).
Конекторите приемат само издания, подписани с ключа, който съдържа
тяхната версия. С друг ключ (изгубено или сменено начално число) всяко
обновяване завършва с signature_invalid, докато всеки конектор не бъде
преинсталиран ръчно с версия, съдържаща новия публичен ключ.
Публикуване
CI качва всеки MSI със scripts/publish-release.sh от хранилището на
конектора:
| Версия | Номер | Канал |
|---|---|---|
Етикет vX.Y.Z (release.yml) | X.Y.Z | stable |
Етикет vX.Y.Z-suffix | X.Y.Z-suffix | dev |
Всяко качване в main (dev-release.yml) | 0.0.<build>-dev.<commit> | dev |
curl -X POST -H "Authorization: Bearer $SPHERE_RELEASE_TOKEN" \
-H "Content-Type: application/octet-stream" --data-binary @sphere-connector.msi \
"https://hub.entrosity.com/sphere/api/releases/v1/connector?version=0.2.0&channel=stable¬es=Release%20v0.2.0"
Тялото е самият MSI (до 64 MiB). Sphere подписва манифеста му
(proto.ReleaseManifest, компонент sphere-connector: версия, SHA-256 и
размер) с SPHERE_RELEASE_SIGNING_KEY и го съхранява в таблицата
connector_releases, като пази най-новите десет издания.
| Отговор | Значение |
|---|---|
| 201 | Съхранено: {id, version, channel, sha256, size_bytes, created_at}. |
401 unauthorized | Грешен или липсващ токен, или SPHERE_RELEASE_TOKEN не е зададен. |
409 release_exists | Тази версия вече е публикувана (скриптът го приема за успех: повторни изпълнения на работен поток). |
422 validation | Не е семантична версия, канал, различен от stable или dev, или празно тяло или по-голямо от 64 MiB. |
503 releases_disabled | SPHERE_RELEASE_SIGNING_KEY не е зададен. |
Предлагане на обновявания
Sphere предлага най-новото издание от SPHERE_CONNECTOR_UPDATE_CHANNEL
(stable: стабилните издания; dev: dev и стабилните), когато конектор
изпрати hello, и на всеки 5 минути (releases.rollout), на онлайн
конекторите, които:
- обявяват възможността
update(версии сRELEASE_PUBLIC_KEY); - работят с по-стара версия (на конектор, чиято версия не е семантична,
например локална версия
dev, никога не се предлага обновяване); - нямат отворена задача
update_agentи не им е предлагана същата версия през последния час (connectors.update_version,connectors.update_requested_at).
Предложението е задача update_agent (изтичане на времето след 30
минути) с връзки за изтегляне, валидни 2 часа, и с инсталатора на
текущата версия за връщане назад, ако Sphere още го пази. Какво прави
конекторът: Конектор на Sphere → Самообновяване.
Връзките за изтегляне
(GET /api/releases/v1/connector/{releaseID}/{file}?t=…) не изискват
вход: t е срок на валидност и HMAC с ключ, изведен от ключа за
подписване, а грешна или изтекла връзка връща 404. Изтегляне на
конектора и новите токени за регистриране получават връзки, валидни
един час.
Фонови задачи
Бекендът изпълнява задачите си в PostgreSQL (River):
| Задача | Кога | Какво |
|---|---|---|
realtime.sweep | На всеки 30 секунди | Маркира като офлайн конекторите, мълчали 3 минути (видеорекордерите им стават unknown, потоците им – не на живо); прекратява просрочените задачи на конекторите и изпраща повторно непотвърдените (след 60 секунди). |
streams.sweep | На всеки 10 секунди | Премахва зрителите без keepalive от 45 секунди; спира потоците на живо, които никой не е гледал през времето им за изчакване (SPHERE_LIVE_IDLE_GRACE, 5 минути, за подпотоците; SPHERE_LIVE_IDLE_GRACE_MAIN, 2 минути, за основните потоци; задача sphere.stream.stop), и възпроизвежданията на записи веднага щом зрителят им изчезне (sphere.playback.stop, без изчакване); забравя спрените потоци след 10 минути. |
nvr.reconcile | На всеки 2 минути | Изпраща отново sphere.nvr.apply за видеорекордери, чийто конектор е онлайн, но не държи желаното състояние (свързан, но отчетен като unknown или disconnected или с по-стари идентификационни данни; несвързан, но още влязъл), непроменени от 2 минути и без отворена задача за прилагане. |
releases.rollout | На всеки 5 минути | Предлага най-новото издание на конектора на онлайн конекторите, които се обновяват сами (Предлагане на обновявания). Не прави нищо без SPHERE_RELEASE_SIGNING_KEY. |
alarms.partitions | Ежедневно | Създава месечните дялове за аларми два месеца напред. |
retention.cleanup | Ежедневно | Вижте Съхранение. |
Освен това всеки отчет за състоянието на конектор се сравнява с това, което искат зрителите: поток, който той публикува, но никой не иска (или който е спрян), се спира отново, а желан поток на живо, който не е отчитал 45 секунди, се стартира отново, дори ако е бил на живо (например след рестартиране на конектора). Възпроизвеждане на запис, което вече не отчита, е стигнало края си: то приключва и не се стартира отново.
Колко бързо тръгва камера
Измерено в продукция на 2026-10-09 (подпотоци, H.265, Dahua): камера, която никой не е гледал, се показва за 4,1–5,3 секунди, а камера, чийто поток още върви – за 1,6–2,8 секунди. Съставните части:
| Стъпка | Време |
|---|---|
| Конекторът отваря потока във видеорекордера и го публикува (само когато потокът не върви) | 1,9–2,6 с |
| Зрителят чака следващия ключов кадър на камерата | 1–2 с при подразбиращия се за Dahua интервал от 2 секунди |
| Установяване на WebRTC в браузъра | около 0,6 с |
Какво ги скъсява:
- Времето за изчакване държи неизползваните потоци включени, така че
връщането към камера пропуска стартирането във видеорекордера
(
SPHERE_LIVE_IDLE_GRACE,SPHERE_LIVE_IDLE_GRACE_MAIN, по-горе). - Потокът се смята за пуснат на живо веднага щом задачата за стартиране на конектора успее, а не при следващия му отчет за състоянието. Браузърът подготвя WebRTC връзката (оферта, ICE), докато камерата стартира, а конекторът отваря връзката си с медийния сървър (TCP, TLS), докато видеорекордерът отговаря, а не след това.
- Оптимизиране за изглед на живо на страницата на видеорекордер скъсява интервала между ключовите кадри на подпотоците на камерите до 1–4 секунди (Видеорекордери).
Жизненият цикъл на потоците в подробности: API на Sphere → Гледане на видео, Протокол на конектора на Sphere.
Съхранение
Ежедневна задача retention.cleanup изтрива старите данни на порции от
10 000 реда:
| Данни | Пазят се |
|---|---|
| Журнал с аларми | SPHERE_RETENTION_ALARM_DAYS, за всеки тенант. Алармите се съхраняват в месечни дялове; месецът се изтрива изцяло, след като целият е по-стар от срока, така че алармите се пазят между срока и срока плюс един месец. |
| Приключили задачи на конекторите | Замяната на тенанта (settings.retention.job_days, 7–730), иначе SPHERE_RETENTION_JOB_DAYS. |
| Одитен журнал | Замяната на тенанта (settings.retention.audit_days, 30–3650), иначе SPHERE_RETENTION_AUDIT_DAYS. |
| Токени за регистриране | 30 дни след изтичането или отмяната им. |
| Приключили сесии в Hub, използвани step-up токени | Един час след приключването им; след изтичането им. |
Администраторите на тенанта задават замените в настройките на тенанта
(PATCH /tenants/{tenantID}, API на Sphere).
sphere_retention_rows_deleted_total{category} брои какво е премахнато.
База данни и миграции
Sphere има собствена база данни. Миграциите са вградени в изпълнимия файл
(entrosity-sphere.backend/db/migrations) и се прилагат от migrate up:
| Миграция | Добавя |
|---|---|
0001_init | Копието на Sphere на тенантите, потребителите и ролите от Hub (tenants, users, tenant_memberships, състояние на синхронизацията с Hub, приключили сесии, използвани step-up токени), sites, audit_log само за добавяне, enrollment_tokens, connectors (с курсора за аларми alarms_last_seq), jobs и защита на ниво ред с ролята sphere_app. |
0002_video | nvrs (криптирани идентификационни данни с версия, желано състояние и отчетено състояние), cameras, streams и stream_viewers, журнала alarms, разделен на месечни дялове, с функциите за дяловете, и saved_views. |
0003_view_splits | Запазените изгледи приемат всички разделяния на мрежата: layout 1, 4, 6, 8, 9, 16, 25, 36 или 64 (преди 1, 4, 9 или 16). При връщане назад новите разделяния стават 9 или 16, като се пазят най-много 16 камери. |
0004_connector_releases | connector_releases (инсталаторите с версия, канал, SHA-256, размер, подпис и бележки; глобални редове, четими от всеки тенант и записвани само от глобални операции) и update_version и update_requested_at на конекторите (последното предложено обновяване). |
- Изолация на тенантите: всяка таблица на тенант има политика за
защита на ниво ред; сървърът работи като
sphere_app(NOBYPASSRLS). Препратките между таблиците на тенантите са съставни ключове(tenant_id, id), така че препратка между тенанти е невъзможна. - Само за добавяне:
sphere_appне може да променя или изтриваaudit_log(съхранението чисти чрез отделна функция) и може само да потвърждаваalarms(може да променяacked_atиacked_by, нищо друго; съхранението изтрива дялове). - Паролите на видеорекордерите се съхраняват само криптирани
(
credentials_enc). - Аларми, чието време е извън месечните дялове, попадат в
alarms_defaultи се преместват, когато се създаде дялът за техния месец.
Резервни копия и възстановяване
deploy/scripts/backup.sh прави дъмп на базата данни sphere, когато тя
съществува, до останалите: backups/db/sphere-<timestamp>.dump
(pg_dump -Fc, проверен чрез обратно прочитане), изтриван заедно с
другите дъмпове след дните за съхранение.
deploy/scripts/restore.sh при SPHERE_ENABLED=true спира sphere и
sphere-media, възстановява дъмпа sphere-… от същото изпълнение на
резервното копие, ако има такъв (създава наново базата данни и ролята
sphere_app), изпълнява sphere-migrate и стартира отново sphere и
sphere-media.
Дъмпът съдържа паролите на видеорекордерите, криптирани със
SPHERE_CREDENTIALS_KEY: възстановяването изисква същия ключ. Алармите,
записани след направата на резервното копие, не са във възстановената
база данни и конекторите не ги изпращат отново: те изтриват алармите,
след като сървърът ги потвърди.
Наблюдение
GET /healthz(жизненост) иGET /readyz(готовност: базата данни отговаря; показва също дали копието на данните от Hub е актуално,staleслед 5 минути, без да се проваля) на слушателя на API. Публично:https://hub.entrosity.com/sphere/api/v1/healthz.- Метрики за Prometheus на
SPHERE_METRICS_ADDR(:9094), сред тяхsphere_ws_connections(свързани конектори),sphere_jobs_total{type,status},sphere_job_dispatch_seconds,sphere_http_request_duration_seconds,sphere_platform_syncs_total,sphere_platform_sync_age_seconds,sphere_sse_subscribers,sphere_retention_rows_deleted_total,sphere_river_queue_depthиsphere_db_pool_connections. - Журналите са в JSON при
prod. MediaMTX пише журнал на нивоwarn; отказано публикуване или гледане се записва от бекенда на нивоdebug(media access refused).
Локална разработка
Средата за разработка на entrosity-infra пуска Sphere до Hub
(Настройка за разработка):
-
deploy/.env.exampleима блок за Sphere (SPHERE_*на :8083, hook на :8084, метрики на :9094, тайни за разработка,SPHERE_MEDIA_PUBLISH_URL=rtsp://localhost:8554,SPHERE_PUBLIC_URL=http://localhost:5175/sphere), аPLATFORM_PRODUCT_TOKENSна Hub съдържа токена наsphere. -
Създайте базата данни веднъж:
docker compose -f deploy/docker-compose.yml exec postgres createdb -U rmm sphere. -
Стартирайте медийния сървър – продукционната конфигурация, насочена към бекенда на хоста:
docker compose -f deploy/docker-compose.yml --profile sphere up -d sphere-mediaТой слуша на 8554 (RTSP, без криптиране), 8889 (WHEP) и 8189 (медия), обявява
127.0.0.1и питаhttp://host.docker.internal:8084/media/auth. -
В
entrosity-sphere.backend:make migrate, след товаmake dev(API на :8083). -
В
entrosity-sphere.frontend: неговият сървър за разработка на :5177. -
Отворете
http://localhost:5175/sphere/. Сървърът за разработка на Hub препраща/sphere/apiкъм :8083 (с премахната представка),/sphere/mediaкъм :8889 (като запазва адресите на WHEP сесиите под/sphere/media, както Caddy) и/sphereкъм :5177. -
За видео пуснете конектор със симулатора:
sphere-connector enroll --server http://localhost:5175/sphere --token <token>, след товаmake devвentrosity-sphere-connector(Изпробване на Sphere със симулатора).