Ansible 2.10 и Collections: мигрируем десятки модулей из ansible-core и обновляем AWX
Ansible 2.10 разделяет монорепо: модули уходят в отдельные коллекции. Описываем миграцию requirements.yml и обновление AWX в боевых плейбуках.
Ansible 2.10 выходит с полным разделением экосистемы: ansible-core содержит только builtin-модули, остальное - в отдельных коллекциях community.general, amazon.aws и других
В апреле мы обновляли AWX до 11 и разбирались с collections на практике. Тогда казалось, что основная работа по миграции позади - коллекции есть, requirements.yml заполнен, FQCN в ролях прописан. Оказалось, нет: с выходом Ansible 2.10 история получила продолжение, и довольно ощутимое.
Что изменилось в 2.10
Если в 2.9 разделение на коллекции было концептуальным - модули переезжали постепенно, старые имена в плоском namespace работали через compatibility shim - то в 2.10 Red Hat сделал это структурно. ansible как пакет теперь это тонкая обёртка, которая тянет за собой ansible-core плюс набор коллекций. Сам ansible-core содержит только то, что Ansible называет builtin: ansible.builtin.copy, ansible.builtin.template, ansible.builtin.service и ещё несколько десятков модулей фундаментального уровня.
Всё остальное - community.general, community.network, amazon.aws, google.cloud, cisco.ios, вендорские коллекции - теперь отдельные пакеты с собственными версиями и собственным жизненным циклом. Это значит: если в requirements.yml нет явного collections: блока, а плейбук использует что-то вроде postgresql_db или ec2_instance - оно просто не найдётся. Никакого shim, никакого fallback.
У клиентов, которых мы ведём в managed-сопровождении, плейбуки писались начиная с версий 2.5-2.7. За это время накопился зоопарк модулей: часть из того что было в core, часть из Galaxy-ролей, часть - собственные модули. И почти нигде не было явного requirements.yml с коллекциями - потому что это требование появилось только сейчас.
Инвентаризация: что конкретно переехало
Первое что пришлось сделать - пройтись по плейбукам и выписать все используемые модули без FQCN. Это оказалось неприятной работой, потому что часть задач использует {{ item }} с loop и модуль передаётся через переменную - grep это не ловит.
Наиболее часто встречавшиеся модули и куда они уехали:
postgresql_db,postgresql_user-community.postgresql(раньше были вcommunity.general, но выделились в отдельную коллекцию)docker_container,docker_image-community.dockerec2_instance,s3_bucket-amazon.awsnmcli,hostname,timezone-community.generalwin_feature,win_service,win_copy-ansible.windowsvmware_vm_facts,vmware_guest-community.vmware
У одного клиента обнаружилось, что в плейбуке для деплоя приложения используется uri (это ansible.builtin, всё хорошо), postgresql_user (нужен community.postgresql) и docker_container (нужен community.docker) - три разных пространства имён в одном файле, и раньше это работало потому что всё было в одном монорепо Ansible.
requirements.yml: до и после
До 2.10 у большинства проектов файл выглядел примерно так - только роли из Galaxy:
- roles:
- src: geerlingguy.java
version: 1.9.6
- src: geerlingguy.nginx
version: 2.7.0
После миграции в него добавился блок collections:
collections:
- name: community.general
version: ">=3.0.0"
- name: community.postgresql
version: ">=1.1.0"
- name: community.docker
version: ">=1.2.0"
- name: ansible.windows
version: ">=1.3.0"
roles:
- src: geerlingguy.java
version: 1.9.6
- src: geerlingguy.nginx
version: 2.7.0
Версии пришлось зафиксировать явно - иначе ansible-galaxy collection install -r requirements.yml при каждом запуске тянет latest, и воспроизводимость сборки ломается. Для AWX это особенно важно: там коллекции устанавливаются при синхронизации проекта, и неожиданный мажорный апгрейд коллекции в середине ночи - плохая идея.
AWX: что поменялось в схеме
С AWX у нас шла параллельная история. После апрельского обновления до AWX 11 стояла версия 12, и к январю надо было двигаться дальше - в репозитории появились breaking changes в Execution Environments, которые Red Hat двигает как замену традиционному подходу с установкой коллекций прямо в контейнер.
Execution Environments - это образы, которые содержат ansible-core, коллекции и Python-зависимости вместе. Red Hat двигает их как замену нынешней схеме, поддержка заявлена в будущих минорных версиях AWX. Мы пока не переходим на EE полностью - у клиентов это потребовало бы отдельного CI-пайплайна для сборки образов. Остаёмся на схеме с requirements.yml в проекте, которую AWX 11-14 поддерживает: при синхронизации проекта AWX запускает ansible-galaxy collection install -r requirements.yml в рабочем каталоге.
Две вещи которые важно знать про эту схему в AWX:
Первое - порядок директорий. AWX ставит коллекции в ~/.ansible/collections/ansible_collections внутри контейнера. Если коллекция уже была там от предыдущего проекта - она не обновится без явного --force. В нашем случае это один раз создало ситуацию когда community.general стояла в версии 2.x, а requirements.yml требовал 3.x - AWX молча взял старую. Решение: в настройках проекта есть опция Clean, которая чистит рабочий каталог при синхронизации. Включили.
Второе - FQCN в шаблонах задач. AWX позволяет запускать отдельные модули из UI как Ad Hoc команды. Там тоже надо писать FQCN - community.general.nmcli вместо nmcli. Без этого AWX 14 не находит модуль и выдаёт ошибку которая выглядит как «модуль не установлен», хотя он установлен - просто без FQCN больше не ищет в collections.
Где сейчас
Три клиентских окружения прошли полный цикл: инвентаризация модулей, заполненный requirements.yml с зафиксированными версиями коллекций, замена коротких имён на FQCN в критичных плейбуках. Критичных - это те, которые запускаются автоматически или по расписанию. Остальные мигрируем по мере того, как в них заходим.
Неприятный момент, который обнаружился в процессе: community.general - это коллекция-помойка, куда попало всё что не нашло лучшего дома. Она уже весит несколько мегабайт и содержит модули для вещей, которые у части клиентов не используются вообще. Устанавливать её целиком ради nmcli и timezone - не идеально. Но пока альтернативы в виде более узких коллекций для этих модулей нет, живём с этим.
Ещё один открытый вопрос - Execution Environments. Текущая схема с requirements.yml работает, но её потолок виден: если у проекта сложные Python-зависимости (например, boto3 определённой версии для amazon.aws), управлять ими через AWX неудобно. Это следующий шаг, но сначала надо закончить миграцию на FQCN - делать два изменения одновременно не хочется.