сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Terraform и Ansible

Ansible: идемпотентность и роли

Ansible и настройка машин

Написал сценарий из четырёх задач и прогнал дважды. Первый прогон: «ok=4 changed=4» - сделано всё. Второй прогон, ничего между ними не менялось: «ok=4 changed=1». Три задачи честно поняли, что делать нечего, а одна отчиталась об изменении - и это ровно та задача, где я вызвал обычную команду оболочки.

Стержень: модули умеют проверять текущее состояние и потому идемпотентны, а прямой вызов команды - нет, и он же портит весь отчёт об изменениях.

// Формулировки: «что такое идемпотентность в Ansible?», «почему changed всегда не ноль?», «где граница между Ansible и Terraform?»

Идемпотентность и отчёт

Модуль тут - готовая единица работы, которая умеет и проверить, и сделать. Устроен он так: сначала смотрит фактическое состояние, потом решает, надо ли что-то менять. Создать каталог, положить файл с нужным содержимым, добавить строку в файл - все три задачи на втором прогоне отчитались «без изменений», потому что всё уже было как надо.

А вызов произвольной команды такой проверки не делает - он просто выполняет. Отчёт при этом честно говорит «изменено», хотя ничего не изменилось. В моём замере именно эта одна задача дала «changed=1» на втором прогоне.

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

идемпотентная задача
сначала проверяет состояние, потом решает, надо ли действовать
отчёт об изменениях
число изменённых задач; ноль означает, что реальность совпала с описанием

Проверочный прогон и порядок

Есть режим, в котором сценарий показывает, что СОБИРАЕТСЯ сделать, ничего не меняя. Проверил: удалил созданный файл и запустил в этом режиме - отчёт показал изменения, а файл на диске так и не появился. Это ближайший аналог просмотра плана в инструментах описания инфраструктуры.

Работает он не всегда честно: задачи с прямым вызовом команд в этом режиме обычно пропускаются, и если следующая задача зависит от их результата, картина получается неполной. В моём прогоне одна задача действительно оказалась пропущена.

// Второе принципиальное отличие от инструментов описания инфраструктуры: здесь порядок задач важен. Сценарий выполняется сверху вниз, зависимости не выводятся сами. И состояния тут нет: инструмент каждый раз спрашивает саму машину. Отсюда плюс - потерять состояние невозможно, и минус - удалить ресурс, убрав его из описания, нельзя: чтобы что-то снести, надо явно написать задачу «убрать».

проверочный прогон
режим, показывающий планируемые изменения без их применения
порядок задач
выполняются сверху вниз; зависимости не выводятся автоматически

Граница между инструментами

Разделение обычно такое. Инструмент описания инфраструктуры создаёт то, чего не было: сети, машины, кластеры, базы, права. Инструмент настройки приводит в порядок то, что внутри уже созданной машины: пакеты, конфиги, службы, пользователи.

Стык между ними - место, где чаще всего болит. Классические варианты: описание инфраструктуры создаёт машину и запускает настройку через стартовый скрипт; или создаёт, а настройка запускается отдельным шагом конвейера по списку машин из выходных значений.

// И честная оговорка про современную практику: с контейнерами роль инструмента настройки сильно сузилась. Настройка уехала внутрь образа, а машины стали одноразовыми - вместо того чтобы приводить машину в порядок, её просто пересоздают из свежего образа. Инструмент настройки при этом остаётся востребованным там, где машины живут долго: базы на своём железе, сетевое оборудование, машины разработчиков, площадки без контейнеров.

инструмент настройки
приводит в нужный вид содержимое уже созданной машины
одноразовая машина
её не чинят и не донастраивают, а пересоздают из свежего образа

Как отвечать: «Что такое идемпотентность в Ansible и почему changed никогда не ноль?»

Идемпотентность здесь означает, что задача сначала проверяет фактическое состояние и действует, только если надо. Я прогонял сценарий из четырёх задач дважды: первый раз «изменено 4», второй - «изменено 1», и эта единица - задача с прямым вызовом команды оболочки. Она не умеет проверять состояние и потому всегда отчитывается об изменении. Это и есть ответ на вторую половину вопроса: если в сценарии есть такие задачи, отчёт перестаёт быть сигналом. А отчёт - главный инструмент проверки: прогнал, увидел ноль изменений, значит, реальность совпадает с описанием. Чиню это тремя способами: заменяю команду на подходящий модуль, если он есть; ставлю условие, при котором задача считается изменившей что-то; или условие, при котором она вообще выполняется.

Ответ связывает механику с практической ценностью отчёта и даёт три конкретных способа починки. Именно сломанный отчёт об изменениях и есть настоящая проблема.

На чём валятся

  • Пишут сценарий на прямых вызовах команд и теряют идемпотентность вместе с отчётом.
  • Не проверяют, что второй прогон даёт ноль изменений.
  • Полагаются на проверочный прогон там, где половина задач в нём пропускается.
  • Ждут, что удаление задачи из сценария снесёт созданное. Нужна явная задача на удаление.
  • Пытаются настраивать долгоживущие машины там, где проще пересоздать их из образа.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 7, остальные разбираются в тренажёре.

  1. #dvo_ansible1 / 5
    Ansible и Terraform часто держат вместе. По какой границе их разводят?
    A)Ansible для облака, Terraform для железных серверов
    B)Terraform ведёт учёт ресурсов, Ansible настраивает хосты
    C)Terraform для приложений, Ansible для сетевого оборудования
    D)Ansible применяют в проде, Terraform — только в тестовых средах
    показать ответ и разбор
    +B)Terraform ведёт учёт ресурсов, Ansible настраивает хосты

    // разбор: Terraform ведёт учёт: знает, что создал, и потому умеет удалять лишнее и приводить набор ресурсов к описанному. Ansible состояния не хранит — он приезжает на существующие хосты и приводит их конфигурацию к нужной, но не знает, что удалить, если задачу убрали из плейбука. Отсюда типовая связка: инфраструктуру поднимает Terraform, начинку настраивает Ansible, а в неизменяемой модели вторая часть заменяется сборкой образов.

  2. #dvo_ansible2 / 5
    Плейбук должен накатываться на веб-серверы, но не на серверы БД. Чем это задаётся?
    A)Инвентарём: группы хостов + hosts на группу
    B)Условием when на каждой задаче по имени хоста
    C)Отдельным плейбуком-копией под каждый сервер
    D)Тегами задач, запуская нужные через --tags
    показать ответ и разбор
    +A)Инвентарём: группы хостов + hosts на группу

    // разбор: В Ansible область действия задаёт инвентарь: хосты разложены по группам (webservers, dbservers), а в плее указывают hosts: webservers — плейбук идёт только на них. Группы можно комбинировать (webservers:&production), задавать групповые переменные. when-условия по имени хоста и копии плейбуков — хрупкие обходные пути; теги же фильтруют задачи внутри плея, а не выбирают целевые хосты.

  3. #dvo_ansible3 / 5
    Нужно перезапускать сервис только если задача реально изменила его конфиг. Как это делают в Ansible?
    A)Ставить restart отдельной задачей после каждого прогона
    B)Проверять конфиг модулем shell и рестартить по diff
    C)Рестартить в начале плейбука на всякий случай
    D)notify → handler, срабатывает лишь при changed
    показать ответ и разбор
    +D)notify → handler, срабатывает лишь при changed

    // разбор: Для «перезапусти, только если поменялось» служат handlers: задача, изменившая конфиг (статус changed), делает notify «restart service», а сам handler выполняется один раз в конце плея и только если его кто-то уведомил. Так рестарт происходит ровно при реальном изменении, сохраняя идемпотентность (повторный прогон без изменений ничего не перезапускает). Безусловный рестарт этот принцип нарушает.

  4. #dvo_ansible4 / 5
    В плейбуках и переменных есть пароли и ключи. Как хранить их, не открывая в репозитории?
    A)Держать в отдельном файле vars и не коммитить его
    B)Шифровать их ansible-vault, в git лежит зашифрованное
    C)Класть пароли в инвентарь открытым текстом
    D)Кодировать значения base64 перед коммитом
    показать ответ и разбор
    +B)Шифровать их ansible-vault, в git лежит зашифрованное

    // разбор: Секреты в Ansible шифруют ansible-vault: отдельные значения (!vault) или целые файлы переменных хранятся в git в зашифрованном виде, а при запуске расшифровываются по паролю/ключу (--ask-vault-pass, vault-id, интеграция с менеджером секретов). Так секреты остаются под контролем версий, но не открыты. Некоммитимые файлы теряются и рассинхронятся, а base64 — это кодировка, а не защита.

  5. #dvo_ansible5 / 5
    Что такое плейбук (playbook) в Ansible?
    A)Отчёт о выполненных на серверах командах
    B)Список серверов с их адресами и группами
    C)Готовый образ операционной системы для развёртывания
    D)YAML-файл с задачами, которые применяют к указанным хостам
    показать ответ и разбор
    +D)YAML-файл с задачами, которые применяют к указанным хостам

    // разбор: Плейбук описывает желаемое состояние набором задач: поставить пакет, положить конфиг, запустить сервис. Список серверов лежит отдельно, в инвентаре — так один и тот же плейбук применяют к разным группам хостов.

дальше

Теорию прочитали. Навык ставится повторением

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