ADG Оставить заявку
Блог Автоматизация 5 мин чтения

Ansible playbook вместо чеклиста: провизионируем новый Linux-сервер за 20 минут

Перевели ручной чеклист развёртывания нового сервера в Ansible playbook. Первые 50 строк YAML уже заменили час рутины - и теперь это идемпотентно.

Контекст момента

Ansible 1.8/1.9 набирает популярность как agentless-инструмент автоматизации Linux-инфраструктуры

Год назад писали про Ansible и идемпотентность в довольно общих словах. Сейчас есть что рассказать конкретнее: как именно мы перевели ручной чеклист развёртывания нового сервера в playbook, что из этого вышло и где ещё спотыкаемся.

Повод простой: в декабре подняли очередной сервер для клиента на сопровождении. Выбрали момент, чтобы сделать это уже не по чеклисту, а полностью через Ansible 1.8. Ниже - что реально произошло, без приукрашивания.

Откуда взялась задача

Чеклист существовал в вики уже года три. Выглядел примерно так: два десятка пунктов, часть из них с пометкой «зависит от клиента», несколько с примечаниями «на RHEL иначе». Когда сервер поднимает один и тот же инженер - всё в голове, работает. Когда задача падает на другого человека или ты сам возвращаешься к этому через три месяца - начинаются вопросы. Пропустил ли sudo-конфиг? Выставил ли правильный timezone? Добавил ли хост в мониторинг?

Принцип простой: если делаешь одно и то же руками больше трёх раз - пора автоматизировать. Мы немного затянули.

Структура playbook

Итоговый base-playbook получился на 180 строк YAML, но костяк - те самые первые 50 - делает основное:

  • Базовые пакеты. vim, htop, curl, wget, lsof, net-tools, chrony или ntp в зависимости от дистрибутива. Модуль apt/yum проверяет наличие перед установкой - запустишь второй раз, ничего лишнего не случится.
  • Временная зона. Один таск через timezone: - и не нужно помнить что на одном клиентском сервере мы выставляли Europe/Moscow через timedatectl, а на другом правили /etc/localtime вручную.
  • SSH-конфиг. Отключение root-логина, разрешённые пользователи, порт. Шаблон Jinja2 с переменными - один и тот же плейбук, разные параметры под разных клиентов.
  • Пользователи и ключи. Список пользователей и их публичные ключи хранятся в переменных инвентаря. Модуль authorized_key идемпотентен - добавляет ключ только если его ещё нет.
  • Zabbix-агент. Ставится из репозитория, конфиг генерируется из шаблона с адресом Zabbix-сервера, сервис включается в автозагрузку. Три таска вместо шести ручных шагов.

Оставшиеся 130 строк - это handlers, проверки через assert, и специфика для CentOS 6 vs CentOS 7 (systemd в CentOS 7 меняет несколько вещей с управлением сервисами).

Что получилось на практике

Подняли сервер из шаблона VMware, прописали в инвентарь, запустили ansible-playbook base.yml -l новый_хост. Через 18 минут сервер был в нужном состоянии: пользователи созданы, SSH перенастроен, Zabbix видит хост, NTP синхронизирован.

Раньше этот же процесс занимал минут 50-60, если делать аккуратно и сверяться с чеклистом. Если делать по памяти - могло быть быстрее, но с риском что-то пропустить.

Самый приятный момент: через неделю запустили тот же playbook повторно, когда потребовалось добавить ещё одного пользователя. Ansible прошёл по всем тасками, ничего лишнего не тронул, только добавил нового пользователя и ключ. Это и есть идемпотентность в деле - не абстрактное свойство, а конкретное «можно запустить ещё раз и не бояться».

Где спотыкаемся

Несколько мест, где всё пошло не так гладко.

Условия под разные дистрибутивы быстро превращают playbook в нечитаемое when: ansible_os_family == "RedHat" через каждые три строки. Мы пока решаем это через group_vars: серверы по дистрибутивам в разных группах, специфичные переменные переопределяются там. Работает, но требует дисциплины при добавлении новых хостов в инвентарь.

Shell-таски без creates: - вечная проблема. Там где нет готового модуля и приходится использовать shell: или command:, идемпотентность надо обеспечивать вручную. Пару раз забыли, и при повторном запуске таск выполнялся заново. Не катастрофа, но неприятно.

Порядок handlers несколько раз удивлял. Ansible запускает handlers в конце play, а не сразу после notify. Если перезапуск сервиса нужен до следующего таска - это нужно явно обрабатывать через meta: flush_handlers. Вроде понятно, но в горячке забываешь.

Про версию 1.8/1.9

Ansible 1.8 вышел в октябре, 1.9 ожидается в начале года. В 1.8 заметно улучшился модуль template и появился нормальный Ansible Vault для хранения секретов - мы наконец перестали класть пароли в plaintext в переменные. Vault шифрует файл целиком: ansible-vault encrypt vars/secrets.yml - и файл уходит в репозиторий в зашифрованном виде.

vault в 1.8 ещё немного сырой: если зашифровал файл, расшифровать его для чтения из командной строки можно только через ansible-vault view, редактировать - через ansible-vault edit. Неудобно когда надо быстро сверить значение. Ждём что в 1.9 это поправят.

Что дальше

Базовый playbook работает. Следующий шаг - разбить его на роли, чтобы можно было переиспользовать отдельные куски: роль ntp, роль zabbix-agent, роль ssh-hardening. Ansible Galaxy как репозиторий готовых ролей уже существует, но большинство публичных ролей пишут под свои предположения о структуре системы - проще написать свою, чем адаптировать чужую.

Есть у нас и другой план: превратить этот playbook в основу для CI-пайплайна, где каждый новый сервер проходит проверку через ansible-playbook --check перед реальным применением. Пока это идея, не реализация.

В целом: 50 строк YAML за вечер - и ручной чеклист стал историей. Не панацея, есть нюансы, но направление очевидное.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.