# Агент обновлений `soniks-agent` — отдельный контейнер рядом с клиентом, который раскатывает образ клиента с портала: читает канал релизов станции, применяет образ в окне между проходами, проверяет его health-gate и откатывается на предыдущий при провале. Агент v1 меняет **только образ клиента** — определения спутников и конфигурацию тракта клиент получает с портала сам. Код и контракт — репозиторий `soniks-agent`; решения — «Агент v1» в [](../roadmap-network.md). ## Что видит владелец На странице настроек станции (`stations//config/`, блок «Обновления»): | Поле | Кто задаёт | Что значит | |---|---|---| | Канал релизов | администраторы сети | `stable` (по умолчанию) или `canary` — какой digest образа станция получает | | Обновления клиента | владелец | `notify` (по умолчанию) — агент только сообщает о новом образе; `managed` — применяет сам | Что агент сделал, видно там же и на странице станции: текущий и предыдущий образ, итог последнего применения (`L1`/`L2`, ошибка), доступный образ канала. ## Включение Агент — сервис **того же** `docker-compose.yml`, что и клиент. Блок `soniks-agent` в шаблоне закомментирован; раскомментируйте его и том `soniks-agent` в `volumes:`, затем: ```bash docker compose up -d ``` Ничего в `.env` добавлять не нужно: агент читает те же `STATION__ID`, `STATION__TOKEN`, `URL__BASE` и `HEALTH__PORT`. Необязательные `AGENT__*` — в [](environment_variables.md). Три условия, из-за которых блок именно такой: * **тот же compose-проект.** `/healthz` клиента не выведен на хост (`ports:` нет), агент читает его по имени сервиса внутри сети проекта; * **каталог станции монтируется по тому же пути, что на хосте** (`${PWD}:${PWD}`, `working_dir: ${PWD}`). Проект, рабочий каталог и файлы конфигурации агент берёт из лейблов своего контейнера и запускает `docker compose` с ними — иначе Docker считал бы это другим проектом. Запускайте `docker compose up -d` из каталога станции: `${PWD}` берётся из оболочки; * **`docker.sock`** — агент управляет контейнером клиента через Docker хоста. Это права root на хосте; отсюда `notify` по умолчанию и режим `managed` только по решению владельца. ## Что агент делает при обновлении 1. Раз в минуту забирает `GET /api/v2/stations//state/` и сравнивает `release.client_image` с образом, на котором поднят клиент. 2. `notify` — строка в логе агента и поле «доступен» на портале. 3. `managed` — образ скачивается сразу, применяется в окне: проход не идёт и до ближайшего дальше `AGENT__WINDOW_IN_MINUTES`. 4. В `docker-compose.override.yml` станции агент вписывает `image:` сервиса `soniks-client` (остальные ключи файла сохраняются) и делает `docker compose up -d soniks-client`. Поэтому ручной `docker compose up -d` после этого поднимает тот же образ, а не тег из `docker-compose.yml`. 5. Health-gate: **L1** — клиент отвечает 200 на `/healthz`; **L2** — `test-flowgraph.sh` в контейнере клиента дожил до таймаута (код 124) и оставил непустой водопад `test.dat`. Конфигурация портала передаётся L2 через окружение. 6. Провал — откат на предыдущий образ и та же проверка L1. Этот digest агент не повторяет `AGENT__RETRY_AFTER_HOURS`, пока в канале не появится новый. Агент не удаляет предыдущий образ: откат берёт его с самой станции. ## Ручной откат и выключение Поправьте `image:` в `docker-compose.override.yml` (или удалите файл, вернув тег из `docker-compose.yml`) и выполните `docker compose up -d soniks-client`. В `managed` агент через минуту применит образ канала снова — переключите станцию в `notify` на портале. Выключить агент — `docker compose stop soniks-agent` или закомментировать блок обратно. ## Диагностика ```bash docker compose logs -f soniks-agent docker compose exec soniks-agent cat /var/lib/soniks-agent/state.json ``` «Compose станции недоступен, только наблюдаю» в логе — каталог станции не смонтирован по пути хоста или агент запущен не из compose. «Портал прислал не digest» — в канале релизов тег, а не `имя@sha256:…`; агент такое не применяет.