Блоки в Ansible: block, rescue и always

Рейтинг: 61% · 6 голосов
Подробный курс по Ansible с прицелом на экзамен RHCE EX294: установка и инвентарь, плейбуки, переменные и факты, Vault, циклы и условия, шаблоны Jinja2, роли и коллекции, Execution Environments и ansible-navigator, управление системами (диски, LVM, cron, SELinux, firewalld). Примеры на RHEL/Fedora. Актуально на 2026.
Ответить
Аватара пользователя
Maksim_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Блоки в Ansible: block, rescue и always

Сообщение Maksim_DevOps »

Оглавление курса (47)
  1. Что такое Ansible и зачем он нужен: автоматизация без агентов
  2. Сертификация RHCE и экзамен EX294: что внутри и как готовиться
  3. Архитектура Ansible: control node, узлы, модули и плагины
  4. Установка Ansible на control node: dnf, pip и версии ansible-core
  5. Подготовка управляемых узлов: SSH, пользователь и sudo
  6. Инвентарь Ansible: hosts, группы и переменные
  7. Настройка Ansible: файл ansible.cfg и приоритеты конфигурации
  8. Host patterns и инструменты командной строки Ansible
  9. Ad hoc команды Ansible: быстрые задачи без плейбука
  10. Ansible playbook: что это такое и как устроен
  11. Структура плейбука: play, task, модули и переменные
  12. Запуск плейбуков: проверка, теги, ограничения и отладка
  13. Параллелизм и порядок выполнения: forks, serial, strategy
  14. Факты Ansible: сбор информации об узлах
  15. Переменные Ansible: типы, объявление и приоритет
  16. Регистрация результатов и специальные переменные
  17. Ansible Vault: шифрование паролей и секретов
  18. Организация инвентаря: group_vars, host_vars и вложенные группы
  19. Динамический инвентарь и инвентарные плагины
  20. Циклы в Ansible: loop, списки и словари
  21. Повтор задачи до условия: until, retries и delay
  22. Условия в Ansible: директива when и логика
  23. Jinja2 в Ansible: выражения, фильтры и подстановки
  24. Обработчики Ansible: handlers, notify и flush_handlers
  25. Обработка ошибок: failed_when, changed_when и ignore_errors
  26. Блоки в Ansible: block, rescue и always (вы здесь)
  27. Управление файлами: модули file, copy, fetch и stat
  28. Архивы и сборка файлов: archive, unarchive, assemble
  29. Точечное редактирование файлов: lineinfile и blockinfile
  30. Шаблоны Jinja2: модуль template и динамические конфиги
  31. Jinja2 продвинуто: фильтры, циклы, макросы и lookup
  32. Модули Ansible: ansible-doc и поиск нужного модуля
  33. Разработка собственного модуля Ansible на Python
  34. Роли Ansible и Ansible Galaxy: переиспользование
  35. Разработка роли Ansible: создание с нуля
  36. Зависимости ролей и requirements.yml
  37. Коллекции Ansible: ansible.posix, community и своя коллекция
  38. Execution Environments: контейнеры для запуска Ansible
  39. Сборка Execution Environment с ansible-builder
  40. ansible-navigator: запуск плейбуков в Execution Environment
  41. Управление SSH-ключами через Ansible: authorized_key
  42. Управление дисками: filesystem, mount и parted
  43. LVM через Ansible: тома, группы и расширение
  44. Планировщик задач: cron и systemd timers через Ansible
  45. Безопасность: hardening SSH и репозитории dnf/yum
  46. SELinux через Ansible: булевы, контексты и порты
  47. Сквозной проект и подготовка к экзамену EX294
Представь типичную ситуацию. Плейбук разворачивает приложение: качает архив, распаковывает, останавливает сервис, накатывает обновление, запускает обратно. На шаге распаковки что-то идёт не так - битый архив, кончилось место на диске. Ansible честно падает на этой задаче и... оставляет тебя с остановленным сервисом и наполовину раскатанным релизом. Прод лежит, а откатывать ты будешь руками в три часа ночи.

В обычном коде ты бы завернул это в try/catch/finally. В Ansible ровно для этого есть блоки - block, rescue и always. Это не просто синтаксический сахар: грамотная обработка ошибок ansible через блоки превращает хрупкий линейный плейбук в управляемый сценарий, который умеет откатываться и прибираться за собой.

Что такое block и зачем группировать задачи

Самое базовое назначение ansible block - сгруппировать несколько задач и навесить на всю группу общие директивы. Вместо того чтобы копировать when, become или tags в каждую задачу, ты пишешь их один раз на блок.

Код: Выделить всё

- name: Настройка веб-сервера на RHEL
  hosts: web
  tasks:
    - name: Установка и запуск nginx
      block:
        - name: Установить пакет nginx
          ansible.builtin.dnf:
            name: nginx
            state: present

        - name: Открыть http в firewalld
          ansible.posix.firewalld:
            service: http
            permanent: true
            immediate: true
            state: enabled

        - name: Запустить и включить nginx
          ansible.builtin.service:
            name: nginx
            state: started
            enabled: true
      become: true
      when: ansible_facts['os_family'] == "RedHat"
      tags: webserver
Директивы become, when и tags применяются ко всем трём задачам внутри. Важная деталь: when на блоке вычисляется для каждой задачи отдельно, и условие как бы складывается с условиями внутренних задач по логическому И. Под Ubuntu/Debian аналогично проверял бы Debian в os_family и ставил пакет через apt, а вместо firewalld был бы ufw - механика блока та же.

Изображение

block + rescue + always: try-catch-finally по-ansible'овски

Теперь главное, ради чего блоки и любят. Полная конструкция выглядит так и читается ровно как try/catch/finally:
  • block - основные задачи (try). Выполняем то, что хотим.
  • rescue - что делать, если в block что-то упало (catch). Сюда управление прыгает при первой же ошибке.
  • always - выполняется в любом случае (finally), упал block или нет.
Ключевой момент про ansible rescue: как только любая задача в block возвращает failed, Ansible бросает остаток блока и переходит в rescue. А самое приятное - если rescue отработал без ошибок, хост считается успешным и плейбук едет дальше. То есть rescue не просто логирует беду, он реально гасит ошибку.

Соберём тот самый сценарий деплоя: пытаемся обновить, при сбое откатываемся, в конце всегда возвращаем сервис в строй.

Код: Выделить всё

- name: Безопасный деплой с откатом
  hosts: app
  become: true
  vars:
    release_dir: /opt/myapp/current
  tasks:
    - name: Обновление релиза с защитой от падения
      block:
        - name: Остановить сервис приложения
          ansible.builtin.service:
            name: myapp
            state: stopped

        - name: Развернуть новый релиз
          ansible.builtin.unarchive:
            src: /tmp/myapp-2.4.0.tar.gz
            dest: "{{ release_dir }}"
            remote_src: true

        - name: Прогнать миграции (тут может упасть)
          ansible.builtin.command:
            cmd: /opt/myapp/bin/migrate --check
          changed_when: false

      rescue:
        - name: Сообщить, что именно упало
          ansible.builtin.debug:
            msg: "Сбой на задаче '{{ ansible_failed_task.name }}'. Откатываемся."

        - name: Откатить релиз из бэкапа
          ansible.builtin.command:
            cmd: /opt/myapp/bin/rollback
          changed_when: true

      always:
        - name: Гарантированно запустить сервис
          ansible.builtin.service:
            name: myapp
            state: started
Что бы ни случилось внутри block - сервис в always всегда поднимется. Если миграция упала, отработает rescue (уведомит и откатит), а потом всё равно зайдёт always. Это и есть схема "попытаться - откатить - всегда прибраться".

Доступ к ansible_failed_task и ansible_failed_result

Внутри rescue Ansible подкладывает две магические переменные, и для отладки они бесценны:
  • ansible_failed_task - сам объект упавшей задачи. Чаще всего берут ansible_failed_task.name, чтобы понять, на каком шаге рвануло.
  • ansible_failed_result - полный результат упавшей задачи: msg, rc, stderr и прочее. Идеально, чтобы достать текст ошибки и, например, отправить в Slack или записать в журнал.

Код: Выделить всё

      rescue:
        - name: Показать причину сбоя
          ansible.builtin.debug:
            msg: >-
              Задача: {{ ansible_failed_task.name }}
              | rc={{ ansible_failed_result.rc | default('n/a') }}
              | {{ ansible_failed_result.msg | default('нет msg') }}
Блоки можно вкладывать друг в друга - вложенный block со своим rescue ловит локальную ошибку, а если не справился, пробрасывает её во внешний rescue. Учти нюанс версий: пробрасывание ansible_failed_task и ansible_failed_result из внутреннего блока во внешний rescue корректно работает начиная с ansible-core 2.14.

Типичные грабли
  • rescue прячет проблему. Если rescue отработал чисто, хост зелёный, и в CI ты можешь не заметить, что деплой на самом деле откатился. Внутри rescue добавляй явный вывод или, если откат недопустим, в конце rescue ставь ansible.builtin.fail, чтобы плейбук всё-таки честно упал.
  • Хендлеры и блоки. notify внутри block работает, но если задача упала и сработал rescue, обычные хендлеры в конце плея не запустятся (Ansible их пропускает при провале плея на хосте). Не рассчитывай на хендлер для критичной уборки - кладируй её в always.
  • Условие на блоке. when на block - это не "выполнить блок, если...", а условие, навешиваемое на каждую вложенную задачу. На register результат самого блока повесить нельзя - блок не возвращает единый результат.
  • always всё равно выполнится. Даже если в rescue ты сделал fail, always отработает до падения. Это фича (прибраться надо всегда), но новички удивляются, почему "после fail ещё что-то выполнилось".
Мини-лаба

Собери руками на тестовой RHEL/Fedora-машине плейбук, который:
  • в block создаёт каталог через ansible.builtin.file и пишет туда файл, а затем намеренно выполняет ansible.builtin.command с заведомо несуществующей командой;
  • в rescue выводит через debug значения ansible_failed_task.name и ansible_failed_result, а затем удаляет недоделанный каталог (state: absent);
  • в always пишет в /var/log сообщение о завершении прогона.
Запусти дважды: с битой командой и с рабочей. Убедись, что rescue срабатывает только при ошибке, а always - оба раза. Потом заверни всё во внешний block/rescue и проверь, как ошибка пробрасывается наружу.

Контрольные вопросы
  • В каком случае выполнится секция rescue, а в каком - always?
  • Что произойдёт с состоянием хоста, если rescue отработал без ошибок?
  • Как внутри rescue узнать имя упавшей задачи и текст её ошибки?
  • Почему критичную уборку лучше класть в always, а не в хендлер?
Итог. block группирует задачи и навешивает общие директивы, а связка block rescue always даёт полноценный try/catch/finally: попытаться, поймать сбой с откатом и уведомлением, всегда прибраться. На EX294 умение писать обработку ошибок через block/rescue/always - это современный, ожидаемый от вас способ, и именно его стоит показывать вместо костылей с ignore_errors. Освой переменные ansible_failed_task и ansible_failed_result - и твои плейбуки перестанут оставлять прод в полураскатанном состоянии.
👍3 ❤️1 🔥 😄 🤔3
Аватара пользователя
dave26
Сообщения: 1
Зарегистрирован: 20 май 2026, 00:43

Re: Блоки в Ansible: block, rescue и always

Сообщение dave26 »

Спасибо, наконец дошло зачем always - раньше пихал перезапуск сервиса в самый конец плейбука и при падении он не отрабатывал. Перенёс в always, теперь сервис всегда поднимается.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
user_anton
Сообщения: 1
Зарегистрирован: 23 май 2026, 10:14

Re: Блоки в Ansible: block, rescue и always

Сообщение user_anton »

А подскажите: если в rescue я делаю ansible.builtin.fail чтобы плейбук всё-таки упал, always при этом отработает или нет? По тексту вроде да, но хочу убедиться перед тем как тащить в прод.
👍 ❤️1 🔥 😄 🤔2
Ответить
← Предыдущая глава
Обработка ошибок: failed_when, changed_when и ignore_errors
Следующая глава →
Управление файлами: модули file, copy, fetch и stat

Все главы курса «Ansible: автоматизация и подготовка к RHCE (EX294)»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое ansible простыми словамиansible для начинающих с чего начатьустановка ansible на linuxansible inventory и hosts файлчто такое playbook в ansibleструктура ansible playbook из чего состоит

Вернуться в «Ansible: автоматизация и подготовка к RHCE (EX294)»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость