Run from the jump host: on each validator it updates the git clone in /opt/cloud-ip-validator, builds the image there, stops and removes the current container and starts a new one from the new image. Run parameters live in an env file (deploy/ansible/env/validator-agent.env, git-ignored, template committed). The image is built before the running container is touched, so a failed build leaves the old container running. Hosts are updated in waves (1, 4, rest) and any failure stops the run. validator_id comes from the inventory and is checked against the running container before it is replaced. Only ansible.builtin modules are used, so the validators need no extra packages. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
108 lines
10 KiB
Markdown
108 lines
10 KiB
Markdown
# Доставка validator-agent на валидаторы (Ansible)
|
||
|
||
Сценарий запускается с jump-хоста и на каждой ВМ-валидаторе: обновляет git-клон в `/opt/cloud-ip-validator`,
|
||
**собирает образ на самом хосте**, останавливает и удаляет старый контейнер `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`).
|
||
|
||
## Подготовка (один раз)
|
||
|
||
```bash
|
||
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.yml` 20 хостов `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`).
|
||
|
||
## Запуск
|
||
|
||
```bash
|
||
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](../../docs/SETUP.md#обновление-образов-после-изменения-кода)) и закоммитьте его вместе с `bin/SHA256SUMS`.
|
||
|
||
### Откат
|
||
|
||
```bash
|
||
ansible-playbook playbooks/deploy-validator-agent.yml -e deploy_ref=<предыдущий коммит или тег>
|
||
```
|
||
|
||
Для тега или коммита клон переходит в detached HEAD; следующий запуск с `deploy_ref=main` возвращает его на ветку.
|
||
|
||
## Что делает сценарий на каждом хосте
|
||
|
||
1. **preflight** — env-файл на jump-хосте существует и в нём задан `VALIDATOR_AGENT_CONTROL_API_URL` (адрес-пример
|
||
`example.com` не принимается); на валидаторе отвечает Docker, есть git и клон, архитектура x86_64; `validator_id` из inventory совпадает
|
||
с `validator_id` работающего контейнера. Показывает текущий контейнер.
|
||
2. **git** — `fetch`, затем клон сбрасывается на `deploy_ref` (`checkout --force`). Через `git`, а не модуль `git`:
|
||
учётные данные, уже настроенные в клоне, не трогаются. Локальные правки отслеживаемых файлов в клоне будут сброшены;
|
||
неотслеживаемые и игнорируемые (`.env.*`) — нет.
|
||
3. **build** — проверка `bin/validator-agent` по `bin/SHA256SUMS`; `docker build --platform linux/amd64` с контекстом в корне репозитория,
|
||
образ получает метку ревизии (`cloud-ip-validator-validator-agent:<хеш>`) и `latest`.
|
||
4. **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 …`.
|
||
5. **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`).
|
||
- **`dubious ownership`, `could not read Username`** — клон принадлежит другому пользователю или учётные данные git есть у другого:
|
||
задайте `git_user`.
|
||
- **`bin/validator-agent` не совпадает с суммой** — в репозитории устарел `bin/SHA256SUMS`: пересоберите бинарник и обновите сумму.
|
||
- **Сборка падает на `FROM alpine:3.20` / `apk add`** — с валидатора нет доступа к Docker Hub / репозиториям Alpine.
|
||
- **Старый образ другого имени остаётся** — сценарий чистит только образы `image_name`; образ с прежним именем удалите вручную (`docker rmi`).
|