> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velesagent.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Сборка и развёртывание контейнеров

> Границы ответственности исходного репозитория Велеса и репозитория развёртывания, слои сборки и правила публикации образов.

# Сборка и развёртывание контейнеров

Исходный репозиторий Велеса владеет сборкой обоих образов, чартом Helm, перечнем
экземпляров и их параметрами. Прежний отдельный репозиторий развёртывания не участвует в
новом конвейере и после перехода может быть архивирован целиком.

## Публикация образов

Файл `.gitlab-ci.yml` сначала при необходимости собирает базовые образы, а затем запускает
две независимые задачи прикладной сборки. Одна собирает `Dockerfile`, вторая —
`nerve/Dockerfile`. В основной ветке прикладные задачи публикуют метки `develop` и `latest`,
как в прежнем конвейере `veles_deploy`.

Задачи выполняются параллельно. Стадия развёртывания ждёт успешного завершения обеих и
использует `develop`; полный и короткий хэши фиксации сохраняются только в аннотациях Pod
для диагностики. Встроенные навыки входят только в образ Велеса. Nerve получает их
эффективный каталог от шлюза и не хранит собственную копию.

## Базовые образы и чистая сборка

Редко меняющиеся системные пакеты и зависимости вынесены в три самостоятельных образа:

* `veles-base` — Debian, Python, Node.js, системные пакеты, зависимости Python и моста;
* `veles-nerve-build-base` — средства и зависимости для сборки Nerve;
* `veles-nerve-runtime-base` — системные и рабочие зависимости для запуска Nerve.

В базовый образ Велеса входят `libreoffice-nogui` и `ffmpeg`. Они доступны агенту и
встроенным средствам Велеса; в образ Nerve эти пакеты не дублируются.

Предварительные образы описаны в `Dockerfile.base` и `nerve/Dockerfile.base`, а прикладные
образы для внутреннего реестра — в `Dockerfile` и `nerve/Dockerfile`. Файл
`Dockerfile.railway` собирает единый образ Велеса и Nerve для основного сервиса Railway.
Файлы `nerve/Dockerfile.railway` и `nerve/railway.toml` сохраняются для совместимости со
старой схемой из двух сервисов. Все варианты Railway собираются самостоятельно из
общедоступных основ. Основы внутреннего конвейера
пересобираются только при изменении базового Dockerfile, манифеста зависимостей или
встроенного сертификата. Обычное изменение исходного кода использует опубликованные основы
и добавляет только код Велеса или Nerve. Если базовые образы были удалены из реестра либо
их требуется освежить принудительно, конвейер основной ветки запускают с переменной
`REBUILD_BASE_IMAGES=true`.

Если входные файлы основы не изменились, задачи `prepare:veles-base` и
`prepare:nerve-bases` остаются в конвейере как необязательные ручные задачи. Это позволяет
повторно создать отсутствующий или ранее не собравшийся образ без фиктивного изменения
Dockerfile. После успешной ручной подготовки следует повторить прикладные задачи сборки,
если они уже успели завершиться ошибкой. Для одновременной автоматической пересборки всех
основ при запуске нового конвейера используется `REBUILD_BASE_IMAGES=true`.

Базовые и прикладные задачи вызывают `docker build` с `--pull --no-cache`. Конвейер не
загружает прошлые образы для кэша, не публикует метаданные промежуточных слоёв и не
использует постоянные каталоги BuildKit, `uv`, `npm` или `apt`. Базовые образы являются
обычными версионируемыми результатами сборки в реестре, а не кешем исполнителя. Временные
данные загрузчиков удаляются в той же команде, в которой устанавливаются зависимости.

Файл `.dockerignore` исключает из контекста неиспользуемые тестовые данные, проектные
примеры, чарт развёртывания и архив Nerve. Исходники, документация, сценарии и сертификаты
остаются доступны соответствующим Dockerfile. Встроенные навыки копируются только вместе с
исходниками Велеса.

Пакеты основного репозитория Debian загружаются через
`http://nexus-r1.alor.ru/repository/apt-debian/`. Адрес записан непосредственно в базовых
Dockerfile и применяется одинаково в GitLab CI и при ручной сборке. Репозиторий обновлений
безопасности остаётся официальным, поскольку отдельный адрес Nexus для него не указан.

Каждая стадия базового образа обновляет сведения `apt` один раз. Node.js 20 для Велеса
копируется из официального образа Node.js, поэтому не требуется подключать NodeSource,
устанавливать его ключ и повторно обновлять сведения о пакетах.

## Развёртывание и индивидуальные ресурсы

После сборки задача `deploy` обновляет экземпляры из `VELES_USERS` посредством чарта
`deploy/helm`. Она запускается только для основной ветки. Ключ шлюза читается из защищённой
переменной `VELES_GATEWAY_TOKEN_<ЛОГИН>` и передаётся Helm через стандартный ввод, а не в
аргументе команды или временном файле.

Перечень пользователей соответствует последней конфигурации прежнего конвейера и включает
`ermakov`. Для нового пользователя также требуются запись в службе имён, настройка
балансировщика и защищённая переменная ключа шлюза; точные шаги перечислены в
`deploy/users/README.md`.

Долговечные отличия пользователя хранятся в `deploy/users/<логин>.yaml`. Этот файл
накладывается после общих значений, поэтому очередное обновление повторно применяет
индивидуальный размер диска, запросы и пределы ЦП и памяти. Ручные изменения посредством
`--set` не являются источником истины и могут быть заменены следующим конвейером.

Для пользователя `balakhnin` файл `deploy/users/balakhnin.yaml` закрепляет размер
постоянного тома `5Gi`.

Существующий PVC можно только увеличивать. Класс хранения должен иметь
`allowVolumeExpansion: true`; уменьшение запроса не уменьшает уже выделенный том и не
должно использоваться как способ освобождения места.

## Запуск серверного контейнера

Для Docker и Kubernetes общая точка запуска находится в `scripts/container-entrypoint.sh`.
Сценарий хранится и используется внутри исходного репозитория Велеса; копировать или
синхронизировать его с отдельным репозиторием развёртывания не требуется. Для команды
`gateway` точка запуска:

1. выбирает постоянный каталог (`VELES_DATA_DIR`, смонтированный `/data/veles` или локальный `/root/.veles`);
2. создаёт конфигурацию и шаблоны рабочей области только при их отсутствии;
3. синхронизирует встроенную документацию;
4. выполняет идемпотентный перенос личностей;
5. передаёт управление шлюзу.

Другие команды без дополнительной подготовки передаются обычной командной строке Велеса. Поэтому `onboard`, `status` и `agent` сохраняют прежнее поведение.

Образ включает существующий `scripts/config.template.json`. При первом запуске точка
входа подставляет в него переменные окружения для обычных настроек. Поля учётных данных
в шаблоне содержат локальные ссылки на зашифрованные секреты и заполняются через Nerve;
открытые значения из окружения в эти поля не подставляются. Без доступного шаблона
создаётся пустой объект, который Велес дополняет значениями по умолчанию.

Сбой шлюза в Docker или Kubernetes завершает основной процесс контейнера с тем же кодом,
после чего перезапуском занимается среда исполнения.

Railway не использует внутренний реестр базовых образов. Корневой `railway.toml` собирает
единый `Dockerfile.railway`, в котором среда Велеса является окончательной стадией, а
собранный сервер Nerve добавляется в `/app/nerve`. Один сервис запускает оба процесса и
публикует только назначенный Railway порт Nerve. Без значения `PORT` от среды Nerve
использует `3080`; в Railway следует выбирать порт, показанный строкой запуска
`[openclaw-ui]` в журнале. Шлюз доступен интерфейсу по адресу `http://127.0.0.1:18790`.

Сценарий `scripts/railway-start.sh` сначала определяет фактическую точку подключения тома.
Значение `RAILWAY_VOLUME_MOUNT_PATH` имеет приоритет над ручной настройкой; в действующем
сервисе том подключён к `/data/veles`. Сценарий не удаляет, не переносит и не заменяет его
содержимое, а безопасно связывает внутренний путь `/root/.veles` с точкой подключения.
Если `/root/.veles` уже содержит другие данные, запуск завершается с ошибкой вместо
автоматического объединения каталогов. Это предохраняет конфигурацию, рабочую область,
память, секреты и историю от потери при переходе со старой схемы.

После подготовки данных сценарий запускает шлюз, ждёт успешной проверки `/health`, затем
запускает Nerve. Завершение любого из процессов останавливает второй процесс и завершает
контейнер с ошибкой, чтобы политика `ON_FAILURE` перезапустила весь сервис. Проверка
`/health` Nerve в совмещённом режиме также возвращает ошибку, если шлюз недоступен.

Nerve читает и редактирует общую рабочую область через локальную файловую систему.
Это не создаёт вторую копию данных: настройки, задачи, навыки, память, секреты и остальные
долговечные сущности по-прежнему принадлежат Велесу и доступны через шлюз. `ffmpeg`,
LibreOffice и встроенные навыки включаются как средства Велеса; отдельная копия навыков
для Nerve не создаётся.

Файлы `nerve/railway.toml` и `nerve/Dockerfile.railway` позволяют временно оставить или
восстановить отдельный сервис Nerve, но основной путь развёртывания использует один сервис.

Все базовые образы включают корневые сертификаты с расширением `.crt` из каталога
`certificates`, в том числе `alor.internal.crt` и `ALOR-IT-CAcert.crt`. До установки
системного пакета сертификатов сборка использует их как временный доверенный набор для
доступа к Nexus по перенаправлению HTTPS, а затем регистрирует штатной командой
`update-ca-certificates`. Сертификаты не являются секретами и одинаковы для всех
экземпляров, поэтому встраивание не создаёт отдельные объекты Kubernetes на каждого
пользователя. Добавление, удаление или ротация сертификата вызывает новую сборку всех
базовых образов. Начальная конфигурация берётся из существующего
`scripts/config.template.json`.

## Прежний репозиторий развёртывания

Репозиторий `veles_deploy` не входит в эту миграцию и остаётся без изменений. После
перехода потребителей на образы, опубликованные самим Велесом, его следует архивировать
целиком, а не продолжать синхронизировать с исходным репозиторием.

Исполнитель GitLab, собирающий образы, должен иметь право публикации в оба существующих
хранилища образов. Учётные данные не передаются в командах сборки: используется уже
настроенная авторизация исполнителя, как в прежнем конвейере развёртывания.
