The real container on the validators is named validator-agent (the image is cloud-ip-validator-validator-agent); the playbook used the image name as the container name, so it would have started a second agent next to the old one with the same validator_id. The clone on the validators is owned by root, so git must run as root (git_user), otherwise fetch fails with "cannot open .git/FETCH_HEAD: Permission denied". Preflight now stops when the host has another container of this agent (by name or image) besides container_name. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
11 KiB
Доставка validator-agent на валидаторы (Ansible)
Сценарий запускается с jump-хоста и на каждой ВМ-валидаторе: обновляет git-клон в /opt/cloud-ip-validator,
собирает образ на самом хосте, останавливает и удаляет старый контейнер validator-agent (образ — cloud-ip-validator-validator-agent)
и поднимает на его месте новый. Параметры запуска агента вынесены в env-файл.
Порядок безопасен: сначала проверки, обновление кода и сборка образа, и только потом замена контейнера. Если что-то
упало до замены, старый контейнер продолжает работать. Простой валидатора — секунды (stop + rm + run).
Требования
| Где | Что |
|---|---|
| jump-хост (Debian 13) | apt install ansible-core; SSH-доступ по ключу ко всем валидаторам |
| валидаторы | Docker, git, клон репозитория в /opt/cloud-ip-validator, sudo без пароля для SSH-пользователя, доступ к Gitea и Docker Hub (alpine:3.20), архитектура x86_64 |
Только модули ansible.builtin: Python Docker SDK и дополнительные коллекции на валидаторах не нужны.
Go на валидаторах не нужен: образ копирует закоммиченный bin/validator-agent (его сумма проверяется по bin/SHA256SUMS).
Подготовка (один раз)
cd deploy/ansible
cp env/validator-agent.env.example env/validator-agent.env
chmod 600 env/validator-agent.env
$EDITOR env/validator-agent.env # адрес control-api, токен, способы самопроверки, таймауты
ansible validators -m ping # проверка связи (20 хостов: validator-1 ... validator-20)
- В
inventory/hosts.yml20 хостовvalidator-1 … validator-20с адресами (ansible_host) и переменнойvalidator_id(vkiplab-v1 … vkiplab-v20, как в control-api). Соответствиеvalidator-N→vkiplab-vNзадано по порядку номеров; сценарий сверяетvalidator_idс тем, что записано в работающем контейнере на хосте, и при расхождении останавливается до замены контейнера.VALIDATOR_AGENT_VALIDATOR_IDв env-файл писать не нужно: сценарий подставляет его из inventory. - Отпечатки хостов запоминаются при первом подключении (
StrictHostKeyChecking=accept-newвansible.cfg); сменившийся отпечаток известного хоста — ошибка. - SSH: пользователь
debianи ключ~/.ssh/vk_cloud_priv.keyна jump-хосте (права 0600) — одинаковые на всех хостах; меняются вinventory/group_vars/validators.yml(ansible_user,ansible_ssh_private_key_file). Для docker и записи env-файла сценарий повышает права черезsudo. - Токен в env-файле можно зашифровать:
ansible-vault encrypt env/validator-agent.env, запускать с--ask-vault-pass. Рабочийenv/validator-agent.envв git не попадает (.gitignore).
Запуск
cd deploy/ansible
ansible-playbook playbooks/deploy-validator-agent.yml --limit vkiplab-v1 # канарейка: один валидатор
ansible-playbook playbooks/deploy-validator-agent.yml # все валидаторы волнами
ansible-playbook playbooks/deploy-validator-agent.yml --check # только проверки (preflight), без изменений
Волны по умолчанию: 1 хост, затем 4, затем все остальные (deploy_serial: [1, 4, "100%"]). Любой сбой в волне останавливает
прогон: следующая волна не начнётся. Все сразу: -e '{"deploy_serial": ["100%"]}'.
Что выкатывается — deploy_ref (по умолчанию main): ветка, тег или коммит. Выкатить нужно запушенный коммит:
валидаторы берут код из репозитория, а не с jump-хоста. После правок кода сначала пересоберите bin/validator-agent
(см. SETUP.md) и закоммитьте его вместе с bin/SHA256SUMS.
Откат
ansible-playbook playbooks/deploy-validator-agent.yml -e deploy_ref=<предыдущий коммит или тег>
Для тега или коммита клон переходит в detached HEAD; следующий запуск с deploy_ref=main возвращает его на ветку.
Что делает сценарий на каждом хосте
- preflight — env-файл на jump-хосте существует и в нём задан
VALIDATOR_AGENT_CONTROL_API_URL(адрес-примерexample.comне принимается); на валидаторе отвечает Docker, есть git и клон, архитектура x86_64;validator_idиз inventory совпадает сvalidator_idработающего контейнера; на хосте нет другого контейнера этого агента (по имени или образу) — иначе рядом со старым запустился бы второй с тем жеvalidator_id. Показывает текущий контейнер. - git — от имени
git_user(на валидаторахroot: клон принадлежит ему)fetch, затем клон сбрасывается наdeploy_ref(checkout --force). Черезgit, а не модульgit: учётные данные, уже настроенные в клоне, не трогаются. Локальные правки отслеживаемых файлов в клоне будут сброшены; неотслеживаемые и игнорируемые (.env.*) — нет. - build — проверка
bin/validator-agentпоbin/SHA256SUMS;docker build --platform linux/amd64с контекстом в корне репозитория, образ получает метку ревизии (cloud-ip-validator-validator-agent:<хеш>) иlatest. - replace — env-файл копируется в
/opt/cloud-ip-validator/deploy/docker/.env.validator(0600; путь закрыт.gitignore), затемdocker stop→docker rm -f→docker run -d --restart unless-stopped --cap-add NET_RAW --env-file …. - verify — ждёт строку
registeredв логе агента (регистрация в control-api), проверяет, что контейнер запущен, без перезапусков и на только что собранном образе. При неудаче хост падает с последними строками лога, следующие волны не стартуют. Затем остаются 3 последних образа с метками ревизий (keep_images), остальные и «висячие» удаляются.
Все шаги можно запускать по тегам: --tags preflight|git|build|replace|verify.
Параметры
env/validator-agent.env — запуск агента (читает deploy/docker/validator-agent/docker-entrypoint.sh):
VALIDATOR_AGENT_CONTROL_API_URL, CONTROL_API_AGENT_TOKEN, VALIDATOR_AGENT_SELF_CHECK_METHODS,
VALIDATOR_AGENT_SELF_CHECK_TIMEOUT_SECONDS, VALIDATOR_AGENT_POLL_INTERVAL_SECONDS, VALIDATOR_AGENT_HTTPS_TIMEOUT_SECONDS,
VALIDATOR_AGENT_ICMP_TIMEOUT_SECONDS, VALIDATOR_AGENT_ICMP_COUNT, VALIDATOR_AGENT_SSH_ENABLED, VALIDATOR_AGENT_SSH_TIMEOUT_SECONDS.
Смена только env-файла не требует изменения кода: достаточно запустить сценарий (контейнер пересоздаётся с новыми значениями).
inventory/group_vars/validators.yml — доставка: repo_dir, repo_remote, deploy_ref, git_user (пользователь, у которого в клоне
настроен доступ к репозиторию; пусто — SSH-пользователь), image_name, container_name, platform, keep_images, restart_policy,
capabilities, log_max_size, log_max_file, stop_timeout, verify_retries, verify_delay, local_env_file. Любой параметр
переопределяется ключом -e.
Разбор сбоев
- «Нет env-файла» / «не задан VALIDATOR_AGENT_CONTROL_API_URL» — см. «Подготовка».
- «в запущенном контейнере validator_id=…, а в inventory …» — соответствие
validator-Nиvalidator_idвinventory/hosts.ymlневерно для этого хоста: исправьте inventory (контейнер при этом не тронут). - Контейнер не прошёл проверку — в сообщении последние строки лога.
registration failed— control-api недоступен с валидатора илиvalidator_idне заведён в control-api. Контейнер остаётся на хосте для разбора (docker logs). Permission deniedна.git/FETCH_HEAD,dubious ownership,could not read Username— git запущен не от владельца клона или учётные данные есть у другого пользователя: задайтеgit_user(на валидаторах —root).- «найден другой контейнер агента» — на хосте есть контейнер с похожим именем или образом, не совпадающий с
container_name: проверьте имя (docker ps -a) и при необходимости удалите лишний контейнер вручную. bin/validator-agentне совпадает с суммой — в репозитории устарелbin/SHA256SUMS: пересоберите бинарник и обновите сумму.- Сборка падает на
FROM alpine:3.20/apk add— с валидатора нет доступа к Docker Hub / репозиториям Alpine. - Старый образ другого имени остаётся — сценарий чистит только образы
image_name; образ с прежним именем удалите вручную (docker rmi).