Docs / Архитектура
Портал и контуры
Портал обслуживает людей и карту инфраструктуры. Контур живёт рядом с Docker-хостом и владеет его данными. Портал никогда не ходит в Docker, контур никогда не знает о других контурах.
Два слоя
| Портал | Контур | |
|---|---|---|
| Роль | Вход, инвентарь, прокси | Docker-хост и его данные |
| БД | portal_data: контуры, серверы, зашифрованные токены | sqlite_data: история, метрики, секреты, настройки |
| Вход | OIDC SSO или токен портала; свои JWT-сессии | Только AUTH_TOKEN |
| API | /api/portal/* + прокси /api/remote/{id}/* | /api/*: граф, действия, настройки |
| Ключ AI / SSO | Хранит и использует | Не участвует в режиме портала |
| Веб-сервер | Отдаёт UI и статику | Может отдавать UI в standalone |
Компоненты контура
| Сервис | Роль | Сеть / доступ |
|---|---|---|
docker-stat | Веб-приложение: сбор, история, UI, API | frontend, backend, control, telemetry |
docker-api | Типизированный /v1 и allow-list Docker API; держит сокет | backend |
compose-runner | up/down/restart/pull с сокетом | control |
volume-scanner | Деревья томов через /var/lib/docker/volumes:ro | backend |
vuln-scanner | Trivy-сканирование образов через docker-api | backend + egress за базой |
metrics-agent | Метрики хоста из /proc | telemetry |
Сеть backend внутренняя (internal: true), как и control и telemetry; наружу смотрит только frontend (портал, AI-провайдер, egress сканера).
Все сервисы публикуются как образы hub.docker-infra.ru/digraph/<service>:<version>; контур и портал ставятся из deploy/contour и deploy/portal.
Docker-агент
Веб-процесс не монтирует docker.sock и не говорит на Docker HTTP API.
Единственный держатель сокета — docker-api, у него две поверхности:
- типизированный
/v1/…— список, inspect, stats, logs, lifecycle, exec по WebSocket, сети, тома, образы, поток событий; - allow-list raw-путей Docker API — только для
volume-scannerиvuln-scanner.
Обе поверхности используют одну политику PRIVILEGES и один кольцевой аудит. Агент вырезает значения Config.Env, не-compose labels и креденшелы из истории слоёв до отправки ответа.
Маршрутизация
Браузер обращается только к порталу; по префиксу пути портал решает, что делать.
| Путь в браузере | Куда уходит | Кто проверяет доступ |
|---|---|---|
/, /assets/…, /config.js | статика портала | публично |
/api/portal/auth/*, /api/portal/health | портал | публично, кроме login |
/api/portal/settings, /inventory, /contours, /servers | БД портала | JWT портала |
/api/portal/ai/* | AI-провайдер портала | JWT портала |
/api/remote/{id}/api/… | контур http://host:port/api/… | JWT портала, затем AUTH_TOKEN контура |
Два разных 401
Ответ 401 может означать две разные вещи:
- истёк или отсутствует JWT портала — UI обновит сессию по refresh-токену;
- контур не принял сохранённый токен — это не проблема сессии портала.
Чтобы браузер не разлогинивал пользователя из-за чужого ключа, прокси переписывает
401 контура в 502 {"code":"contour_unauthorized"}. Такой ответ означает:
откройте сервер в /#/dashboard и введите ключ заново (двойной клик по ноде).
Что где настраивается
| Настройка | Портал | Контур |
|---|---|---|
| Вход пользователя: OIDC или токен портала | ● | — |
| Контуры, серверы и токены контуров | ● | — |
| AI-провайдер: URL, модель, язык, ключ | ● выполняет | — в режиме портала |
| Интервал сбора и retention истории/метрик | — | ● |
| Разделы events/projects/secrets/security | — | ● |
PRIVILEGES | — | ● только env |
| Проекты, секреты, бэкапы, сканер уязвимостей | — | ● |
| Алерты контура и их вебхуки | — | ● |
| Доступность контуров и каналы дежурства | ● | — |
Страницы: /#/settings — настройки портала; /#/contour — настройки выбранного контура (меню → Host → Config).
AI и SSO принадлежат порталу
Ключ AI шифруется SECRET_MASTER_KEY портала, никогда не уходит в браузер
(только факт api_key_set) и не копируется в контуры. UI вызывает
/api/portal/ai/*; портал собирает prompt из контекста, который прислал
интерфейс, и сам стримит ответ провайдера. Заключения хранятся в БД портала и
привязаны к server_id.
SSO — тоже relying party портала: issuer, client ID, secret, redirect и allowlist
хранятся в portal_settings, secret зашифрован. Контур в режиме портала
принимает только токен.
Хранение
- SQLite с WAL и одной writer-сессией; история пишется только при изменении графа.
- Отдельная таймсерия метрик хоста с собственной ретенцией и предохранителями по строкам.
- Срезы хранят хвост логов каждого контейнера — исторические логи доступны после
compose down. - Портал хранит только инвентарь, настройки, сессии и заключения AI.