
Ansible для серверов: inventory, playbook, роли и безопасный rollout
Подробно разбираем Ansible: control node, inventory, модули, идемпотентность, variables, templates, handlers, roles, Vault, check mode, serial rollout и откат.
Содержание
Ansible применяет описанную конфигурацию к одному или многим узлам: устанавливает пакеты, создаёт пользователей, раскладывает файлы и управляет сервисами. Control node запускает автоматизацию, managed nodes получают команды обычно по SSH. Постоянный агент на обычном Linux-сервере не требуется.
Ценность Ansible — повторяемый и проверяемый процесс. Если playbook только переносит набор shell-команд в YAML, он остаётся хрупким. Качественная автоматизация знает желаемое состояние, ограничивает охват, проверяет результат и допускает постепенный rollout.
Control node, inventory и managed node
Control node — машина, где установлен ansible-core и находится проект. Это может быть рабочий компьютер или изолированный CI runner. Managed node — сервер или устройство под управлением.
Inventory отвечает на вопрос «какие узлы входят в группу и как к ним подключаться». Статический INI-вариант:
[web]
web-01 ansible_host=10.20.0.11
web-02 ansible_host=10.20.0.12
[web:vars]
ansible_user=deploy
Имена web-01 и web-02 — стабильные идентификаторы внутри Ansible, ansible_host — адрес подключения. Пароль и private key в inventory не помещают. SSH должен проверять host key, иначе автоматизация не подтверждает, к какому серверу подключилась.
Для облака dynamic inventory получает узлы из API по тегам и проектам. Это уменьшает ручной список, но ошибка фильтра способна расширить охват. Перед изменением смотрите итог:
ansible-inventory --graph
ansible-inventory --host web-01
Первая команда показывает группы, вторая — переменные выбранного узла. Вывод может содержать чувствительные значения, поэтому его не публикуют целиком.
Module лучше произвольной команды
Module выполняет конкретную операцию и возвращает структурированный результат. ansible.builtin.package управляет пакетом, user — учётной записью, template — файлом из шаблона, service — сервисом.
Модули чаще умеют сравнивать текущее и желаемое состояние. Задача state: present не переустанавливает пакет при каждом запуске. shell запускает строку через оболочку и не может сам понять, было ли изменение. Его оставляют для случаев без подходящего модуля и дополняют условиями, проверками и безопасным quoting.
Fully Qualified Collection Name вроде ansible.builtin.template явно указывает источник модуля. Это уменьшает неоднозначность при подключённых коллекциях.
Playbook описывает последовательность
Ниже playbook для двух веб-серверов. Он устанавливает Nginx, создаёт конфигурацию из шаблона, проверяет её и делает reload только при изменении файла.
---
- name: Configure web servers
hosts: web
become: true
serial: 1
tasks:
- name: Ensure Nginx is installed
ansible.builtin.package:
name: nginx
state: present
- name: Render virtual host configuration
ansible.builtin.template:
src: templates/site.conf.j2
dest: /etc/nginx/conf.d/site.conf
owner: root
group: root
mode: "0644"
validate: "nginx -t -c %s"
notify: Reload Nginx
- name: Ensure Nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: Reload Nginx
ansible.builtin.service:
name: nginx
state: reloaded
hosts: web ограничивает группу, become повышает права для системных файлов, serial: 1 обрабатывает по одному узлу. validate проверяет временный файл до замены конечного. Handler вызывается через notify только если template сообщил changed.
Команда проверки зависит от шаблона. В сложной конфигурации Nginx отдельный файл может ссылаться на окружение, поэтому сначала испытайте validate в staging.
Идемпотентность — проверяемое свойство
Идемпотентная задача после достижения состояния не меняет его при повторе. Это позволяет запускать playbook после частичного сбоя. Но слово «декларативный» не создаёт гарантию автоматически.
Источники ложных изменений:
- шаблон содержит текущую дату или случайное значение;
- команда всегда выполняет запись;
- файл форматируется разными инструментами;
- модуль внешнего API неверно сравнивает состояние;
changed_whenустановлен формально;- service restart запускается обычной task при каждом прогоне.
После успешного применения запустите playbook повторно. Ожидайте changed=0, кроме задач, для которых изменение осознанно. Любой неожиданный changed расследуйте: постоянный restart создаёт риск даже при зелёном результате.
Variables и приоритеты
Переменные позволяют применять роль в разных средах. Они могут приходить из inventory, group_vars, host_vars, role defaults, командной строки и других источников. У Ansible есть правила precedence; конфликтующие имена делают результат трудно предсказуемым.
Используйте понятный namespace роли, например web_nginx_worker_connections, задавайте безопасные defaults и проверяйте обязательные значения через assert. Не передавайте всё через -e: extra vars имеют высокий приоритет и способны незаметно перекрыть проект.
Facts — сведения об узле, собранные Ansible: ОС, адреса, память. Их удобно использовать для выбора пакета, но внешний факт не следует считать доверенным секретом. Отключение gather_facts ускоряет play только там, где роли от них не зависят.
Template должен быть предсказуемым
Jinja-шаблон превращает переменные в конфигурационный файл. Экранирование зависит от формата: значение, безопасное для YAML, необязательно безопасно для shell или Nginx. Не собирайте команду конкатенацией непроверенных строк.
Укажите owner, group и mode явно. Для файла с секретом режим обычно строже 0600, а владелец — сервисный пользователь. Содержимое не выводите через debug.
Если приложение поддерживает configtest, используйте validate. Для нескольких взаимосвязанных файлов нужна staging-проверка целого набора либо атомарное переключение подготовленного каталога.
Handlers и порядок применения
Handlers обычно выполняются в конце play. Если несколько tasks уведомили один handler, он запускается один раз. Это снижает число restart.
Иногда конфигурация должна примениться до следующего шага. Тогда используют meta: flush_handlers, но только с ясной причиной. Иначе скрытое изменение порядка усложняет чтение.
Reload перечитывает конфигурацию мягко, restart останавливает процесс. Не подменяйте один другим. Для сервиса без безопасного reload нужен план доступности и последовательное обновление узлов.
Role формирует повторно используемый компонент
Role группирует defaults, variables, tasks, handlers, templates, files и metadata. Хорошая роль имеет узкую ответственность и документированный интерфейс переменных.
Не создавайте «роль всего сервера» на тысячи строк. Разделите базовую безопасность, runtime, приложение и мониторинг, но контролируйте порядок на уровне playbook. Зависимости role не должны неожиданно менять firewall или пользователей.
Коллекции из Ansible Galaxy — внешний код. Фиксируйте версии в requirements, проверяйте источник и обновляйте через review. Автоматическая загрузка latest делает pipeline невоспроизводимым.
Секреты и Ansible Vault
Vault шифрует переменные или файлы в репозитории. Зашифрованный текст можно коммитить, пароль расшифрования — нельзя. Он должен поступать из защищённого хранилища CI или операторского процесса.
Шифрование at rest не мешает задаче случайно напечатать секрет. Используйте no_log: true для чувствительной task, но помните, что это ухудшает диагностику. Файл на managed node всё равно требует строгих прав и ротации.
Внешний secret manager удобнее для динамических краткоживущих credentials. Выбор зависит от масштаба и модели угроз; Vault Ansible и HashiCorp Vault — разные продукты.
Check mode и diff не гарантируют результат
Перед применением production-конфигурации выполните команду из корня Ansible-проекта на control node. Она ограничит проверку узлом web-01 и не должна изменять managed node:
ansible-playbook -i inventory/production.ini site.yml \
--limit web-01 --check --diff
–limit оставляет один canary-узел, –check просит модули прогнозировать изменения, –diff показывает разницу файлов. Diff может раскрыть секреты. Не все модули полноценно поддерживают check mode, а внешнее состояние меняется между проверкой и применением.
Check — дополнительный барьер, не обещание. После него запустите на canary без –check, выполните smoke-тест, затем расширяйте охват.
Ошибки, rollback и partial state
Playbook останавливается на failed task для соответствующего host, но предыдущие изменения уже могли примениться. Это не транзакция. Если обновление пакета прошло, а конфигурация сломалась позже, узел остаётся в промежуточном состоянии.
Для рискованной операции заранее определите rollback: предыдущий пакет или образ, backup файла, обратимую миграцию. Блоки block, rescue и always помогают обработать ошибку, но автоматический откат тоже проверяют.
После сбоя изучите recap по каждому host. Повторный запуск допустим только когда задачи идемпотентны и промежуточное состояние учтено. Опция продолжить любой ценой может размножить дефект.
Безопасный rollout
Для группы серверов используйте canary и serial. Сначала один узел выводится из балансировки, обновляется и проверяется, затем следующий. max_fail_percentage способен ограничить распространение ошибки, но порог нужно понимать с учётом размера группы.
Добавьте pre_tasks для проверки свободного места, версии ОС и доступности backup, post_tasks — для локального сервиса и внешнего пользовательского запроса. Наблюдайте метрики после выпуска, а не только stdout Ansible.
При SSH-проблемах сначала проверьте обычное подключение тем же пользователем и ключом. Руководство по безопасной настройке SSH объясняет host keys и сохранение доступа.
Когда Ansible подходит
Ansible удобен для конфигурации ОС, повторяемых операций и оркестрации умеренного масштаба. Для декларативного управления облачными ресурсами Terraform решает другую задачу. Для приложений в Kubernetes основным источником состояния могут быть манифесты и операторы.
Инструменты сочетаются: Terraform создаёт VM и сеть, Ansible готовит ОС, pipeline публикует приложение. Границы должны быть ясны. Если два инструмента управляют одним файлом или правилом, drift неизбежен.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Нужно ли устанавливать агент Ansible на каждый Linux-сервер?
Обычно нет. Control node подключается к managed nodes по SSH и запускает модули через доступный Python. Однако требования конкретной коллекции и сетевого устройства нужно проверять отдельно.
Гарантирует ли Ansible идемпотентность любого playbook?
Нет. Многие встроенные модули описывают состояние идемпотентно, но shell-команда, неверный changed_when или внешний API могут менять состояние при каждом запуске. Автор обязан проверять повторный прогон.
Заменяет ли Ansible Vault полноценное хранилище секретов?
Не всегда. Vault шифрует данные в проекте, но ключ расшифрования, выдача доступа, ротация и аудит остаются отдельными задачами. Для крупных систем часто используют внешнее secret-хранилище.


