Ansible 5.2 и обновление коллекций: фиксируем зависимости в AWX и перестаём бояться CI
Обновили ansible-core и набор коллекций в AWX-кластере до Ansible 5.2. Разбираем, как зафиксировать версии коллекций в requirements.yml и не получить сюрпризов в CI.
Ansible 5.x (community): регулярные выпуски коллекций, community.general и ansible.posix обновления
Ansible 5.2 вышел в конце января, и на прошлой неделе мы прокатили обновление на AWX-кластер - сначала в staging-окружении, потом в prod. Заодно разобрались с накопившимися расхождениями в версиях коллекций между проектами. Рассказываем что было, что поправили и почему requirements.yml с плавающими версиями - это тихая мина.
Что изменилось в 5.2
Ansible 5.x строится на ansible-core 2.12, и в 5.2 основная активность - в коллекциях, а не в ядре. Из заметного:
- community.general добрался до 4.3.x в составе пакета. Несколько модулей получили новые параметры, один устаревший alias убрали без особых анонсов в changelog верхнего уровня.
- ansible.posix перешёл на 1.3.x - изменения в
ansible.posix.sysctlиansible.posix.firewalld, в основном расширение параметров. - ansible-core 2.12 ужесточил работу с
collections_pathsи стал строже к FQCN в некоторых контекстах, где раньше молча прощал короткие имена.
Всё это звучит управляемо - до первого взгляда в requirements.yml, где написано version: ">=4.0.0".
Как мы получили сюрприз
После обновления AWX один из клиентских проектов упал на стадии синхронизации коллекций. Причина нашлась быстро: в requirements.yml проекта стояло community.general: ">=3.0.0", AWX при синхронизации честно скачал последнюю доступную версию - 4.4.x. А там один из модулей, который использовался в плейбуке, слегка поменял имя обязательного параметра. Не breaking change в классическом смысле - параметр остался, просто старое имя стало deprecated, а поведение при его использовании без явного указания нового изменилось.
Итог: плейбук, который работал без изменений три месяца, упал в CI с невнятным сообщением об ошибке в параметрах задачи.
Это знакомая история - летом прошлого года мы уже наступали на этот же камень при переходе на Ansible 4.0. Тогда сделали вывод, зафиксировали версии в нескольких проектах. Но не во всех. Теперь зафиксировали в оставшихся.
Как зафиксировать зависимости правильно
Принцип простой: версии коллекций в requirements.yml должны быть пиннингом, а не диапазоном. == вместо >=. Обновление - осознанное действие, а не побочный эффект синхронизации проекта в AWX.
Рабочая структура collections/requirements.yml, к которой мы сейчас пришли:
collections:
- name: ansible.posix
version: "==1.3.0"
- name: community.general
version: "==4.4.0"
- name: community.crypto
version: "==2.1.0"
- name: community.postgresql
version: "==1.7.0"
- name: ansible.windows
version: "==1.9.0"
- name: community.windows
version: "==1.8.0"
Файл хранится в git, обновляется отдельным коммитом с явным описанием что именно и зачем. При следующей синхронизации AWX берёт ровно то, что написано, - никаких неожиданностей.
Несколько практических наблюдений из этого обновления:
Первое - ansible.posix стоит выделять явно. В некоторых старых проектах он не был указан в requirements.yml вообще - просто подтягивался транзитивно через основной пакет ansible. После обновления AWX это поведение стало менее предсказуемым. Лучше прописывать явно, версию - фиксировать.
Второе - changelog коллекций надо читать отдельно. Release notes к Ansible 5.2 как пакету перечисляют только самое важное. Реальные изменения в community.general живут в changelog самой коллекции на GitHub. Перед обновлением версии коллекции в requirements.yml стоит пробежаться по CHANGELOG.rst - обычно это пять минут, которые сохраняют час отладки потом.
Третье - staging обязателен, но недостаточен. У нас есть staging-AWX, и мы катим туда изменения первыми. Но staging воспроизводит только те плейбуки, которые запускаются регулярно. Плейбук «разворачивает новый сервер с нуля» запускается редко - и именно он сломался в prod, потому что в staging его просто не прогоняли при обновлении.
Проверка после обновления
После каждого обновления коллекций мы прогоняем минимальный чек-лист:
ansible-galaxy collection list- убеждаемся что установлены именно зафиксированные версииansible-lintпо ключевым ролям - ловим предупреждения о deprecated параметрах- dry-run плейбуков (там где есть
--checkрежим) - смотрим что plan не падает с ошибкой модуля
Последний пункт звучит очевидно, но на практике его легко пропустить когда обновление выглядит «просто минорным». community.general 4.4.0 от 4.3.0 - это минорная версия, какие там могут быть проблемы. Могут.
Где сейчас
После фиксации версий во всех проектах картина стала заметно спокойнее. AWX-синхронизации предсказуемы, CI не преподносит сюрпризов по субботам. Обновление до следующей версии коллекции - теперь маленький, но явный ритуал: посмотреть changelog, обновить версию в requirements.yml, прогнать в staging, закоммитить.
Для managed-сопровождения это важно особенно: клиент не должен узнавать об изменениях в Ansible-коллекциях через внезапно сломанный деплой в пятницу вечером. Версионирование в requirements.yml - простой способ держать этот класс проблем под контролем.
Ansible 5.x в целом работает стабильно. ansible-core 2.12 пока никаких неожиданностей не принёс. Следующее плановое обновление - когда выйдет 5.3, смотрим на changelog коллекций заранее.