Ansible 2.0: мигрируем с 1.9 на пилотном стенде - блоки, новый движок задач и сломанные модули
Ansible 2.0 вышел в январе с блоками rescue/always, переписанным движком задач и новым API. Делимся чеклистом миграции с 1.9 - что сломалось и почему.
Ansible 2.0 вышел в январе 2016 с поддержкой блоков rescue/always, переработанным движком задач и новым Python API
Ansible 2.0 вышел. Не RC, не dev-сборка - релиз. Мы его ждали с осени, и в первую же неделю января взяли пилотный стенд на сопровождении и попробовали переехать. Результат: в целом работает, блоки - это хорошо, три старых модуля сломались, один час разбирательств с deprecated-синтаксисом.
Что нового в 2.0
Главное, ради чего вообще смотришь на мажорный релиз:
- Блоки (
block/rescue/always). Наконец-то можно обернуть группу тасков в блок и обрабатывать ошибки структурированно - как try/catch в нормальном языке.rescueвыполняется при падении любого таска внутри блока,always- в любом случае. - Переработанный движок выполнения задач. В 1.x параллелизм и порядок выполнения форков порой вёл себя неожиданно. В 2.0 движок переписан с нуля - в теории это должно убрать ряд гонок и странного поведения при использовании
serial. - Новый Python API. Если вы дёргали Ansible из своего кода через внутренние классы - вас ждёт сюрприз: старый API убран. Теперь есть
PlaybookExecutorи нормальная точка входа. - Роли: зависимости и управление. Роли стали чуть более управляемыми - улучшена обработка зависимостей между ролями.
Также в 2.0 убрали несколько давно deprecated параметров и модулей - вот тут и начались наши приключения.
Как выглядит блок rescue/always на практике
До 2.0 типичный сценарий «попробуй, если сломалось - откати» в playbook делался либо через ignore_errors: yes с последующей проверкой register-переменной, либо вообще выносился в отдельные play-файлы с условиями. Некрасиво и ломко.
Теперь это выглядит так:
- block:
- name: накатить новый конфиг nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: reload nginx
- name: проверить конфиг
command: nginx -t
rescue:
- name: откатить конфиг на предыдущий
copy:
src: /etc/nginx/nginx.conf.bak
dest: /etc/nginx/nginx.conf
- name: сообщить в мониторинг об инциденте
uri:
url: "{{ alert_webhook }}"
method: POST
body: '{"text": "nginx config rollback on {{ inventory_hostname }}"}'
always:
- name: убедиться что nginx запущен
service:
name: nginx
state: started
Читается в разы лучше старого варианта с ignore_errors и when: deploy_result.rc != 0. Мы уже переписали несколько playbook-ов с деплойными процедурами - там, где раньше жили костыли, теперь нормальная обработка ошибок.
Что сломалось при миграции
Вот здесь началась честная жизнь. Три вещи потребовали вмешательства:
Первое - модуль accelerate убран полностью. В 1.x была возможность использовать accelerate-режим для ускорения соединений. Мы его давно не использовали активно, но в паре старых playbook-ов он был явно прописан. Ansible 2.0 при встрече с accelerate: true в play просто падает с ошибкой. Лечится удалением строки.
Второе - параметр sudo в тасках заменён на become. В 1.x писали sudo: yes / sudo_user: postgres прямо в таске. В 2.0 это надо переписать на become: yes / become_user: postgres. Параметр sudo в 2.0 ещё принимается, но с предупреждением - поэтому лучше сразу переписать, чем потом разбираться почему вывод замусорен warnings-ами.
Третье - несовместимость в модуле get_url в части параметра sha256sum. В 2.0 он переименован в checksum с префиксом типа: checksum: "sha256:abc123...". Старый синтаксис падает. Нашли в двух playbook-ах, которые скачивают дистрибутивы и проверяют контрольную сумму.
Итого час работы на переписывание старых playbook-ов - и стенд поехал нормально.
Чеклист миграции с 1.9 на 2.0
Прогнались по всем playbook-ам перед переходом и составили список того, что нужно проверить:
sudo:/sudo_user:- заменить наbecome:/become_user:во всех тасках и play.accelerate:- удалить, если есть.get_urlсsha256sum:- переписать наchecksum: "sha256:<hash>".include:с условиями черезwhen:- в 2.0 поведениеincludeсwhenна уровне таска изменилось. Если раньше условие применялось к каждому таску внутри, теперь поведение стало строже - проверяйте результаты на своих playbook-ах.- Собственный Python-код, дёргающий Ansible API - если есть обёртки или скрипты, использующие внутренний Python API Ansible, их нужно переписать под новый
PlaybookExecutor. - Кастомные модули и callback-плагины - проверить совместимость: API для плагинов тоже изменился.
Быстрая проверка перед миграцией - запустить ansible-playbook --syntax-check и ansible-playbook --check на всех playbook-ах ещё под 1.9, а после установки 2.0 - повторить. Несоответствия всплывут сразу.
Про новый движок задач
На нашем стенде разницу в скорости не почувствовали - инфраструктура небольшая, пара десятков хостов. Говорят, на сотнях серверов разница ощутима, но проверить это нам пока негде. Что реально ощутили: пропало одно странное поведение при serial: 1 с notify - раньше handler иногда срабатывал не на том хосте, теперь всё чисто.
Итог
Переход занял у нас один рабочий день: полчаса на установку 2.0 в виртуальном окружении, час на исправление deprecated-синтаксиса, час на прогон тестовых playbook-ов, остаток - на разбор поведения блоков и переписывание пары процедур деплоя.
Блоки rescue/always уже оправдали переход - несколько мест в playbook-ах, которые мы стеснялись показывать, стали читаемыми. Остальное - рабочая эволюция, без сюрпризов.
На прод пока не переключаем - хотим прогнать 2.0 ещё пару недель на пилотном стенде. Но и серьёзных препятствий для перехода не видим.