Skip to content

Обзор агента

Агент — единственный процесс управления на ноде. Запускает Xray как дочерний процесс, держит стрим к backend (gRPC API) и приводит Xray к полученному NodeConfig. Собственных решений о конфигурации агент не принимает: он исполнитель desired state.

flowchart TB
    DS["DesiredState (revision N)"] --> DIFF["diff: NodeConfig ↔ фактическое состояние Xray"]
    DIFF -->|применимо на лету| API["Xray API: add/remove inbound, user, outbound"]
    DIFF -->|требует рестарта| GEN["полный конфиг → xray run -test → рестарт"]
    API --> OK["ApplyResult(N)"]
    GEN --> OK
  1. Агент строит фактическое состояние: список инбаундов, пользователей, аутбаундов из Xray API + собственный учёт того, что API не отдаёт (правила маршрутизации, сертификатные файлы).
  2. Считает diff с NodeConfig.
  3. Применяет: добавление/удаление пользователей, инбаундов, аутбаундов — горячо через Xray API; изменения, которые Xray не умеет на лету (правила маршрутизации, параметры существующего инбаунда), — генерацией полного конфига, валидацией xray run -test и рестартом процесса.
  4. Отправляет ApplyResult. Ошибка любого шага — success: false с текстом; состояние Xray при провале валидации не меняется.

Применение идемпотентно: повторный NodeConfig с той же ревизией даёт пустой diff. Промежуточных статусов нет — либо нода на ревизии N, либо нет.

Хот-патч против рестарта. Массовые ежедневные операции (клиенты появились/ушли/сменили ключ) всегда попадают в горячий путь — рестартов при обычной эксплуатации нет. Рестарт происходит при редких структурных изменениях (новый профиль, правила маршрутизации, цепочки) и стоит секунды даунтайма ноды; существующие соединения рвутся, клиенты переподключаются автоматически.

/var/lib/astral-agent:

Файл Назначение
identity/ Приватный ключ + клиентский сертификат + CA (Безопасность)
last_config.json Последний применённый NodeConfig + ревизия
usage.buffer Неподтверждённые дельты трафика (Трафик)
certs/ PEM-файлы сертификатов для Xray

При старте без связи с backend агент поднимает Xray из last_config.json — нода обслуживает клиентов при недоступной панели. Кэш не источник истины: после переподключения обычный reconciliation приводит ноду к актуальной ревизии.

Агент — супервизор процесса Xray: падение → рестарт с экспоненциальным backoff + повторное применение последнего состояния; инцидент виден в StatusReport (xray_running, uptime). Команда restart_xray из панели — тот же механизм принудительно.

Агент держит кольцевые буферы последних строк своего лога и лога Xray. По команде get_logs отдаёт хвост, по start_log_stream — шлёт новые строки в стрим до stop_log_stream. На диск ноды логи Xray в объёме не пишутся (privacy: меньше следов трафика на ноде).