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

Ansible Collections: мигрируем legacy-роли и настраиваем Nexus-прокси для Galaxy

Ansible 2.9/2.10 делает Collections основным способом дистрибуции ролей. Разбираем миграцию, FQCN, requirements.yml и внутренний Nexus-прокси вместо прямого Galaxy.

Контекст момента

Ansible Collections становятся основным способом дистрибуции ролей начиная с Ansible 2.9/2.10 - Galaxy переориентируется на collections вместо отдельных ролей

Когда Ansible 2.9 вышел в конце прошлого года, мы пробежались по release notes и отметили Collections как «интересно, разберёмся позже». Потом команда Ansible объявила план 2.10, где часть модулей должна переехать из core в collections - и стало понятно, что «позже» заканчивается. Разобрались заранее, пока не пришлось в авральном режиме.

Что изменилось и зачем

До Collections ролевая экосистема Ansible держалась на Galaxy с отдельными ролями: ansible-galaxy install geerlingguy.docker - и вперёд. Проблема в том, что роль живёт сама по себе: никаких зависимостей на конкретные версии модулей, нет пространства имён, конфликты имён между ролями разных авторов решались «на глазок». Для пары ролей в небольшом проекте это не страшно, но у нас их накопилось за несколько лет прилично.

Collection - это пакет с пространством имён вида namespace.collection, который может содержать роли, модули, плагины, фильтры и тесты разом. Версионируется через semver. Galaxy умеет с ними работать как с единицей дистрибуции. Идея правильная: примерно то же, что Terraform сделал с модулями в частном реестре, только для Ansible.

Структура и FQCN

Коллекция живёт по пути ~/.ansible/collections/ansible_collections/namespace/collection/ или в collections/ внутри проекта. Внутри стандартная структура:

adg/
  infra/
    roles/
      base_linux/
      postgres_cluster/
    plugins/
      modules/
      filter/
    galaxy.yml

galaxy.yml - манифест: namespace, name, version, authors, зависимости от других коллекций. Наш namespace - adg, первая коллекция назвали infra.

Отсюда вытекает FQCN - Fully Qualified Collection Name. По плану 2.10: вместо просто postgresql_query будет community.postgresql.postgresql_query, вместо docker_container - community.docker.docker_container. В плейбуках, которые написаны под 2.8 и старше, модули вызывались короткими именами - в Ansible 2.9 это пока ещё работает через обратную совместимость, но по дорожной карте 2.10 маппинг уберут. Лучше переписывать сразу.

У нас переход занял пару вечеров: прошлись grep-ом по плейбукам по паттерну ^ - name: и для каждого task-а сверились с документацией, в какую коллекцию переехал модуль. Скучная работа, но разовая.

requirements.yml теперь двойной

Раньше requirements.yml описывал только роли:

roles:
  - name: geerlingguy.docker
    version: 6.0.1

Теперь добавился раздел collections:

collections:
  - name: ansible.netcommon
    version: ">=1.0.0"
  - name: f5networks.f5_modules
    version: 1.0.0
  - name: adg.infra
    version: ">=0.3.0"

roles:
  - name: geerlingguy.nginx
    version: 2.8.0

Устанавливается одной командой: ansible-galaxy install -r requirements.yml. Роли и коллекции ставятся параллельно. Версионирование с range-операторами работает так же, как в pip - >=, !=, точная версия.

Внутренний Nexus как прокси Galaxy

Прямой выход на galaxy.ansible.com в продакшн-окружении нас не устраивает по тем же причинам, что и прямой registry.terraform.io - см. как мы настраивали Terraform-реестр через GitLab. Те же соображения: контроль над тем, что реально устанавливается, кэш на случай недоступности upstream, возможность разместить внутренние коллекции рядом.

Nexus Repository Manager 3.x умеет работать с Ansible Galaxy через тип репозитория proxy. Настройка прямолинейная:

  1. Создаём proxy-репозиторий с Remote URL https://galaxy.ansible.com и форматом raw.
  2. Создаём hosted-репозиторий для внутренних коллекций.
  3. Объединяем в group.

Дальше в ansible.cfg указываем наш Nexus вместо публичного Galaxy:

[galaxy]
server_list = nexus_group, nexus_internal

[galaxy_server.nexus_group]
url = https://nexus.internal.company/repository/ansible-group/
auth_url = https://nexus.internal.company/service/rest/v1/security/saml
token = {{ lookup('env', 'NEXUS_ANSIBLE_TOKEN') }}

[galaxy_server.nexus_internal]
url = https://nexus.internal.company/repository/ansible-internal/
token = {{ lookup('env', 'NEXUS_ANSIBLE_TOKEN') }}

Токен в CI через переменную окружения, в ansible.cfg не хранится. В managed-сопровождении мы не кладём секреты в репозиторий - это не обсуждается.

ansible-galaxy опрашивает серверы из server_list по очереди: сначала group (там community-коллекции через прокси), потом internal (там наша adg.infra). Если коллекция не найдена нигде - ошибка. Всё прозрачно.

Обратная совместимость и что с ней делать

В Ansible 2.9 короткие имена модулей пока работают - плейбук с docker_container: без namespace не упадёт немедленно. Но по дорожной карте 2.10 маппинг сохранится только через файлы _redirects с [DEPRECATION WARNING] в логах, а потом уберут и это.

Мы решили не тянуть с переходом: депрекейшн-предупреждения в CI превращаются в шум, который все начинают игнорировать, а потом удивляются почему что-то сломалось. Переписали все task-и на FQCN за один проход. Плюс прописали в .ansible-lint правило fqcn-builtins чтобы новый код без FQCN не проходил lint.

Роли, которые мы перенесли в adg.infra, теперь вызываются как adg.infra.base_linux вместо просто base_linux. В playbook-ах поменяли все roles: секции. Немного многословнее, зато сразу понятно откуда роль.

Где сейчас

adg.infra версии 0.4.1 живёт в нашем hosted-репозитории на Nexus. Внутри - четыре роли, которые раньше болтались по разным репозиториям россыпью. CI публикует новую версию через ansible-galaxy collection publish при появлении тега. Потребители прописывают adg.infra: ">=0.4.0" в requirements.yml и получают обновления при следующем ansible-galaxy install.

Боль от самой миграции - один раз и прошла. Зато теперь при переходе на Ansible 2.10, когда он выйдет, мы не будем гадать, что именно переехало и куда: коллекции версионированы, зависимости зафиксированы, Nexus кэширует. GitHub Actions пайплайн для этого описывали отдельно, принцип тот же.

Одно наблюдение напоследок: Galaxy UI для collections на момент написания ощутимо сырее, чем для ролей. Поиск работает не так как ожидаешь, документация коллекции рендерится не всегда. Это рабочий момент, но если планируете публиковать внутренние коллекции - Nexus с его UI окажется удобнее, чем полагаться на Galaxy в качестве основного хранилища.

Контакт

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

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