Тестирование и проверка перед прод
Урок 19 - проверяем playbook до того, как он коснётся боевого сервера.
«Лучший способ узнать, что playbook сломает прод - прогнать его сначала вхолостую, а не на проде».
Перед боевым запуском playbook стоит проверить: что синтаксис верен, что он сделает на самом деле, что он идемпотентен и не нарушает best practices. У Ansible для этого есть встроенные инструменты.
Проверка синтаксиса и сухой прогон
# Проверить синтаксис без выполнения
ansible-playbook site.yml --syntax-check
# Сухой прогон: показать, что было бы сделано, ничего не меняя
ansible-playbook site.yml --check
# То же, но с показом конкретных изменений в файлах
ansible-playbook site.yml --check --diff
Режим --check (dry-run) проходит все задачи, но не применяет изменения - только сообщает, что было бы changed. --diff вдобавок показывает построчную разницу в файлах. Это бесценно перед прод-выкатом.
Линтер ansible-lint
# Проверить playbook на соответствие best practices
ansible-lint site.yml
ansible-lint ловит типичные проблемы: использование command вместо модуля, отсутствие FQCN, незакавыченные mode, задачи без name, потенциальную неидемпотентность. Это автоматический ревьюер твоих playbook'ов.
Проверка идемпотентности
Главный тест зрелости playbook - двойной прогон. Запусти playbook дважды подряд: первый раз - привёл систему в порядок (могут быть changed), второй раз - всё должно быть ok и ноль changed. Если второй прогон что-то меняет - в playbook есть неидемпотентная задача.
Прогон 1: changed=5 ok=10 <- система настроена Прогон 2: changed=0 ok=15 <- ИДЕМПОТЕНТНО (хорошо!) Если Прогон 2: changed=2 <- ПРОБЛЕМА: где-то не check-then-act
# Тест идемпотентности: второй прогон должен дать changed=0
def run_playbook(state):
changed = 0
if state.get("nginx") != "installed":
state["nginx"] = "installed"; changed += 1
if state.get("config") != "deployed":
state["config"] = "deployed"; changed += 1
# НЕИДЕМПОТЕНТНАЯ задача (всегда что-то делает) - для контраста:
# state["counter"] = state.get("counter", 0) + 1; changed += 1
return changed
system = {}
print("Прогон 1: changed =", run_playbook(system)) # 2
print("Прогон 2: changed =", run_playbook(system)) # 0 -> идемпотентно
print("Прогон 3: changed =", run_playbook(system)) # 0
Попробуй сам ▶ Второй и третий прогоны дают changed=0 - playbook идемпотентен. Раскомментируй строку со счётчиком - и каждый прогон станет changed, показав неидемпотентную задачу, которую надо чинить.
Как работает под капотом
В режиме --check модули вызываются в специальном «проверочном» режиме: они вычисляют, нужно ли изменение, и сообщают результат, но не применяют его. Не все модули поддерживают check-режим одинаково (особенно сырой command) - это нормально, Ansible пометит такие задачи как пропущенные в проверке.
Частые ошибки
- Тестировать сразу на проде. Сначала staging, сначала
--check --diff, потом боевой запуск. - Игнорировать ansible-lint. Его замечания - это и есть накопленный опыт сообщества о том, что ломается.
- Не делать двойной прогон. Без проверки идемпотентности неочевидные баги всплывут на проде.
Best practices
- Перед прод-выкатом всегда:
--syntax-check, затем--check --diff, затем staging. - Встрой
ansible-lintи двойной прогон в CI - пусть проверяет каждый коммит. - Доводи playbook до состояния «второй прогон = все ok» - это эталон идемпотентности.
В реальной работе
Проверки перед прод-выкатом выстраивают в конвейер, который проходит каждый коммит. В CI обычно стоят три ступени: ansible-lint ловит стилевые и потенциально опасные конструкции, --syntax-check отсекает синтаксические ошибки, а на тестовом хосте playbook прогоняется дважды - чтобы поймать неидемпотентность. Для серьёзных ролей подключают molecule: он в одноразовом контейнере поднимает чистую систему, применяет роль, проверяет результат тестами и отдельно гоняет idempotence-сценарий. Такой конвейер превращает «надеюсь, не сломается» в «доказано, что работает». Привычка прогонять --check --diff на staging перед каждым продом - дешёвая страховка, которая много раз окупается, показывая неожиданные изменения до того, как они дойдут до боевых серверов.
Итоги
Перед прод-запуском проверяй playbook: --syntax-check для синтаксиса, --check --diff для сухого прогона, ansible-lint для best practices, двойной прогон для идемпотентности. Эти проверки ловят ошибки до того, как они дойдут до боевых серверов. Дальше соберём всё в целостный прод-проект.