Ansible Pull: автономные узлы, cron и отказоустойчивость
Когда push-модель не подходит: разбираем Ansible Pull, его архитектуру, типовые грабли и готовые рецепты для автономных или изолированных окружений.
Ansible Pull: автономные узлы, cron и отказоустойчивость
Ansible Pull — это режим, при котором узел сам инициирует получение конфигурации, а не ждёт команды от центрального контроллера. Это переворачивает привычную push-модель с ног на голову и решает задачи, где классический Ansible бессилен.
Когда выбирать Pull вместо Push
Push (классический Ansible) требует:
- Доступности SSH от контроллера к хостам.
- Открытого пути через NAT/файрволы.
- Централизованного учёта инвентаря.
Pull нужен, когда:
- Хосты за NAT или в изолированных сегментах (DMZ, производственные сети).
- Машины часто появляются и исчезают (эпемерные инстансы, edge-устройства).
- Требуется автономность: узел должен выжить без связи с контроллером.
- Нужно масштабировать на тысячи хостов без узкого горлышка в виде одного бастиона.
Архитектура и компоненты
1. ansible-pull (CLI)
Утилита, которая:
- Клонирует репозиторий с плейбуками (
git cloneили аналоги). - Запускает указанный плейбук локально (
ansible-playbook). - Записывает логи (обычно в
/var/log/ansible-pull.log).
Типовая команда:
ansible-pull \
-U https://git.example.com/infra/ansible.git \
-d /opt/ansible-pull \
-i inventory/hosts.ini \
playbooks/site.yml \
--extra-vars "env=prod" \
-v
2. Планировщик (cron / systemd timer)
Pull бесполезен без автозапуска. Варианты:
Cron (просто и надёжно):
# /etc/cron.d/ansible-pull
*/15 * * * * root /usr/bin/ansible-pull -U https://git.example.com/infra/ansible.git -d /opt/ansible-pull >> /var/log/ansible-pull.log 2>&1
Systemd timer (лучше для логирования и зависимостей):
# /etc/systemd/system/ansible-pull.service
[Unit]
Description=Ansible Pull
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/ansible-pull -U https://git.example.com/infra/ansible.git -d /opt/ansible-pull
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/ansible-pull.timer
[Unit]
Description=Run Ansible Pull every 15 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=15min
Persistent=true
[Install]
WantedBy=timers.target
3. Репозиторий как источник правды
Всё хранится в Git. Структура:
infra/ansible/
├── playbooks/
│ ├── site.yml # Входная точка
│ └── roles.yml
├── roles/
├── inventory/
│ └── hosts.ini # Статический или минимальный
├── requirements.yml # Зависимости ролей
└── ansible.cfg # Локальные настройки
Self-registration и идентификация
Главная боль Pull — как хост понимает, кто он?
Решения (от простого к сложному):
-
По hostname (просто):
Вansible.cfgили через--extra-vars:ansible-pull --extra-vars "hostname={{ ansible_hostname }}"Внутри плейбука:
- name: Apply role by hostname import_role: name: "role_{{ hostname | regex_replace('[^a-z0-9]', '_') }}" -
По метаданным облака (AWS/GCP/Azure):
Скрипт на старте получает IMDS/metadata и пишет временный inventory. -
CMDB lookup (продвинуто):
Хост при первом запуске стучится в API CMDB, получает свою роль и сохраняет в/etc/ansible/facts.d/.
Отказоустойчивость и масштабирование
Кэширование репозитория
Каждый ansible-pull делает git fetch. Это создаёт нагрузку на Git-сервер.
Решение:
- Включить
--checkoutтолько при смене тега/коммита. - Использовать локальный кэш:
--directory /opt/ansible-pull(он уже есть). - Для масштабирования: поставить локальный Git-зеркало (Gitea, GitLab) внутри сегмента.
Обработка сбоев
- Транзакционность: Ansible сам по себе идемпотентен, но убедитесь, что роли не оставляют систему в полуразвёрнутом состоянии.
- Логи: Ротация
/var/log/ansible-pull.log. Используйтеjournaldчерез systemd. - Dead man’s switch: Если хост не применял конфиг N часов — алёрт в мониторинг.
Сравнение: Pull vs Push vs Satellite
| Критерий | Push (классика) | Pull (автономность) | AWX/AAP (Satellite) |
|---|---|---|---|
| Связность | SSH от контроллера | HTTPS/Git от хоста | API/WebSocket |
| Масштаб | Ограничен бастионом | Почти линейный | Зависит от инстансов |
| NAT/DMZ | Проблема | Решение | Решение (через релеи) |
| Сложность | Низкая | Средняя (нужен Git) | Высокая |
Чек-лист внедрения Ansible Pull
- Выбран режим запуска: cron или systemd timer.
- Настроен доступ к Git-репозиторию (deploy key или token).
- Реализована логика self-registration (по hostname или metadata).
- Включено кэширование фактов (
fact_caching). - Настроена ротация логов и мониторинг последнего запуска.
- Проверена идемпотентность ролей (многократный запуск не ломает систему).
- Для масштабирования поднят локальный Git-зеркало.
Мини-пример: Полный цикл
1. Unit-файл (/etc/systemd/system/ansible-pull.service):
[Unit]
Description=Ansible Pull configuration
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=root
ExecStart=/usr/bin/ansible-pull \
-U https://git.internal/ansible.git \
-d /var/lib/ansible-pull \
playbooks/site.yml \
--extra-vars "env=prod"
StandardOutput=journal
StandardError=journal
2. Плейбук (playbooks/site.yml):
- hosts: localhost
connection: local
gather_facts: yes
roles:
- role: base
- role: "role_{{ ansible_hostname | lower }}"
3. Запуск и проверка:
systemctl enable --now ansible-pull.timer
journalctl -u ansible-pull.service -f
ansible-pull --check --diff # Сухой прогон
Ansible Pull — это не «костыль», а архитектурный выбор для распределённых систем. Он жертвует централизованным контролем ради выживаемости и масштабируемости узлов.
См. также: