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

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 ещё пару недель на пилотном стенде. Но и серьёзных препятствий для перехода не видим.

Контакт

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

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