Pull to refresh

Comments 22

Идемпотентность — ключевое требование к Ansible-ролям.
Система после каждого запуска должна приходить в одинаковое состояние

Расскажите, как это выглядит на практике. Допустим, в версии 1 роль делала apt-get install libfoo. В версии 2 роли libfoo больше не нужна и она перестала делать apt-get install. Вопрос. Как привести машины, на которых ранее прогонялась версия 1, в одинаковое состояние с машинами, на которых сразу выполняли версию 2? Удалять в роли пакет? Нельзя, может он другим ролям нужен, не?

Добавить libfoo в эти самые другие роли, не?

А если таких ролей не оказалось? Кто удалит libfoo?

Как вариант, делаем отдельный таск удаления пакета libfoo, если он установлен и прогоняем по нужной группе хостов. Навешиваем тэг таске для установки пакета libfoo, и при следующем запуске роли этот тэг игнорируем.

Я бы не стал так делать. Когда на инфру иду - прогоняю роль драйраном - о том что кто-то, когда-то пакет удалял таской или скипом - я не знаю. А значит - неожиданные изменения в выводе, паника, ругань, проклятия в адрес того кто руками работает.

Давайте разберемся.

Во первых речь зашла о запуске двух разных версий роли на инфраструктуру.

Во вторых если речь о вспомогальном пакете- библиотеке, напрямую не влияющием на функционал ПО из роли (например jq) - я бы грохнул, без зазрения совести. Если же речь о пакете - зависимости, то либо он не нужен, так как меняется версия, устанавливаемого ПО (а значит меняются переменные - версии и ни о какой идемпотентности после запусков не может быть речи), либо в новой версии у нас появился пересобранный deb пакет без зависимости. А если другим ролям всё таки этот пакет нужен - то смотри пункт про проверку зависимостей. И пошагово:

  1. Роль А версии 1 установила зависимость.

  2. Роль Б подтвердила наличие зависимости.

  3. Роль А версии 2 удалила зависимость при apt install -y.

  4. Роль Б установила зависимость.

  5. Роль А версии 2 не внесла изменений при apt install -y.

И пошагово

Эм в смысле, вы предлагаете вечно хранить все версии роли? Что будем делать когда древняя версия сломалась? Ну там сертификат протух или урл сменился или ещё какая хрень?

Да. Именно версионирование я и исповедую. Поменялся урл - в новой версии инвентаря - задам новый. Хранить вечно - избыточно, но иметь возможность отката - необходимо.

Кстати, спасибо за идею.

Не забывайте про SOLID. Принцип единой ответственности никто не отменял. Это существенная смена функционала. Т.е. в вашем случае пишем дополнительную проверку на наличие версии и формируем проведение в зависимости от потребностей (оставляем как есть/удаляем и ставим новую).

Кстати, я обычно делаю versionlock для пакета - это прям про идемпотентность, если на тачке пасётся ещё кто нибудь с котом кроме меня. При управляемом обновлении поконтурно указываю новую.

оставляем как есть/удаляем и ставим новую

Как роли принять решение об удалении если она не знает о существовании других ролей, которые могут не хотеть удаления?

Роль не знает ничего об окружении и других ролях. Про вспомогательный пакет я уже писал. apt yum dnf rmp не удаляют "чужие" используемые зависимости.

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

Например, в ходе установки какого-то ПО понадобилось включить ip_forward. На первый раз решил включить руками, а потом это не требуется (можно запамятовать). Вот такие моменты помогает вычислить возвраты к первому состоянию ВМ.

Ещё рекомендую использовать мультироли. Каждая суброль должна выполнять маленький блок и быть независимой. Как раз теги помогут вызвать именно ту самую суброль, которая нужна. А meta поможет настроить между ними зависимости в случае необходимости.

Например, вам необходимо установить ПО, которое деплоится только через Docker Compose. Вот тут и пригодится зависимость через meta, которая устанавливает Docker.

Примеры очень упрощённые, но думаю суть вы поняли.

Опять по порядку, на основании собственно опыта.

Например, в ходе установки какого-то ПО понадобилось включить ip_forward. На первый раз решил включить руками

Один раз включаю руками, второй отлаживаю плэйбук, третий качу новой версией роли. Любой чих должен быть описан - так документируется инфраструктура как код.

Например, вам необходимо установить ПО, которое деплоится только через Docker Compose

Значит ставим Compose как зависимость. Вызывать тегами отдельную роль - для меня странно. Я придерживаюсь подхода в котором в любой роли теги имеют одинаковое именование. При вашем подходе, вместо изолированного конфигурирования роли А ( тег config) я пройдусь по по всему кластеру.

Про мультироли наверное самый яркий пример - установка отказоустойчивого кластера postgres. В некоторых случаях наверное это более понятная концепция, нежели вязать через CI/tower последовательный деплой.

no_log: true хорошо применять в проде. А как быть со средой дев, когда нам нужно проводить отладку и видеть чувствительные данные?

Можно использовать переменные

no_log: "{{ rolename_env_nolog }}"

Меняем на деве - радуемся. На проде можно в CI проверку вставить.

Используйте fail, а не assert для понятных сообщений об ошибках.

Позвольте не согласиться. Assert имеет функционал по выводу понятных сообщений как в случае успешной проверки, так и неуспешной.

Пример:

- name: Example assert
  ansible.builtin.assert:
    that:
      - my_param <= 100
      - my_param >= 0
    fail_msg: "'my_param' must be between 0 and 100"
    success_msg: "'my_param' is between 0 and 100"

На вкус и цвет все фломастеры разные. При выборе из этих двух модулей я ориентируюсь на то что было написано до меня, стараясь писать понятные условия-проверки.

Учёл. Исправил.

И всегда добавь в конец роли принудительный вызов хендлеров.

И конечно появляется логичный вопрос - а почему, зачем?

Ответ: потому, что все хендлеры по умолчанию срабатывают не по завершению роли, а по завершению плея. И если в одном плее указано несколько ролей есть секция tasks и post_task, и они завязаны на результат выполнения конкретной роли, то тогда обязательно надо принудительно хендлеры в конце этой роли вызывать.

Не согласен про теги. Теги - зло. Нужно, наверное, отдельную статью написать про это.

С удовольствием ознакомлюсь. Я считаю, что правильно построенная структура тегов сильно ускоряет и упрощает рутину.

Sign up to leave a comment.

Articles