В этом уроке разберём, как ansible-builder превращает декларативный файл execution-environment.yml в Containerfile, как описать зависимости тремя слоями (galaxy, python, system) и как выполнить execution environment build так, чтобы образ был воспроизводимым. В конце соберём рабочий EE с ansible.posix и community.general своими руками.
Что такое Execution Environment и зачем тут ansible-builder
EE - это контейнерный образ, внутри которого лежит всё, что нужно для запуска плейбука: интерпретатор Ansible (ansible-core), ansible-runner как точка входа, набор коллекций и зависимости. По сути это замена старого подхода с "поставь ansible на control node руками". Современный RHCE (EX294 на RHEL 9, AAP 2.2) уже строится вокруг ansible-navigator, который по умолчанию гоняет плейбуки именно в таких EE-образах. На RHEL 10 и AAP 2.5 идея та же.
Сам ansible-builder образы не запускает - он их собирает. Под капотом он читает твой YAML-файл определения, генерирует из него Containerfile (это тот же Dockerfile, только имя файла другое) и отдаёт его в podman (по умолчанию) или docker. То есть сборка ee ansible - это всегда два шага: сгенерировать рецепт и собрать образ. Команда build делает оба за раз.
Ставится инструмент через pip, отдельно от самого Ansible:
Код: Выделить всё
python3 -m pip install ansible-builder
ansible-builder --version

Файл определения execution-environment.yml (version 3)
Сердце сборки - файл execution-environment.yml. Актуальная схема - version 3 (её понимает ansible-builder 3.x). Минимальный, но осмысленный пример:
Код: Выделить всё
version: 3
images:
base_image:
name: registry.redhat.io/ansible-automation-platform/ee-minimal-rhel9:latest
dependencies:
ansible_core:
package_pip: ansible-core==2.16.4
ansible_runner:
package_pip: ansible-runner
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
options:
package_manager_path: /usr/bin/microdnf
base_image - от какого образа отталкиваемся. Для AAP это ee-minimal-rhel9 (минимальный, только ansible-core) или ee-supported-rhel9 (с набором сертифицированных коллекций) из registry.redhat.io - доступ к нему требует логина в Red Hat. Если подписки нет, для учёбы можно взять публичный quay.io/centos/centos:stream9 или образ из community, но тогда ansible-core придётся ставить через тот самый ключ ansible_core.
dependencies - три слоя зависимостей, и это самое важное:
- galaxy - указывает на requirements.yml в формате ansible-galaxy. Сюда идут коллекции и роли.
- python - requirements.txt в обычном pip-формате. Сюда питоновские библиотеки, которые нужны модулям (pywinrm, kubernetes, jmespath и т.п.).
- system - bindep.txt в формате bindep. Это системные RPM-пакеты (компиляторы, dev-заголовки, openssh-clients).
additional_build_steps - произвольные команды Containerfile на нужном этапе. Есть несколько точек врезки: prepend_base, append_base, prepend_galaxy, prepend_final, append_final. Например, положить свой ansible.cfg или прогнать дополнительную настройку:
Код: Выделить всё
additional_build_steps:
prepend_final:
- RUN echo "Сборка кастомного EE для прода"
append_final:
- RUN ansible-galaxy collection list
Практика: сборка ee ansible с ansible.posix и community.general
Собираем рабочий EE. Создаём каталог и четыре файла.
requirements.yml (коллекции из Galaxy):
Код: Выделить всё
---
collections:
- name: ansible.posix
version: ">=1.5.0"
- name: community.general
version: ">=8.0.0"
Код: Выделить всё
jmespath
passlib
Код: Выделить всё
gcc [platform:rpm compile]
openssh-clients [platform:rpm]
git-core [platform:rpm]
Код: Выделить всё
version: 3
images:
base_image:
name: registry.redhat.io/ansible-automation-platform/ee-minimal-rhel9:latest
dependencies:
ansible_core:
package_pip: ansible-core==2.16.4
ansible_runner:
package_pip: ansible-runner
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
options:
package_manager_path: /usr/bin/microdnf
Код: Выделить всё
ansible-builder build -t myee:1.0 -v 3
Код: Выделить всё
ansible-builder create
Проверяем, что образ собрался и что внутри лежат наши коллекции:
Код: Выделить всё
podman images | grep myee
podman run --rm myee:1.0 ansible --version
podman run --rm myee:1.0 ansible-galaxy collection list
Код: Выделить всё
ansible-navigator run site.yml --execution-environment-image myee:1.0 -m stdout
Код: Выделить всё
podman tag myee:1.0 registry.example.com/automation/myee:1.0
podman login registry.example.com
podman push registry.example.com/automation/myee:1.0
Типичные грабли
- version: 3 vs version: 1. Старые гайды показывают синтаксис v1 с ключами вроде ansible_config на верхнем уровне. На ansible-builder 3.x он не соберётся. Всегда начинай файл с version: 3.
- Нет доступа к registry.redhat.io. base_image из ee-minimal требует podman login registry.redhat.io с учёткой Red Hat. Без подписки бери публичный базовый образ и ставь ansible-core через package_pip.
- EE только для RPM-образов. Слой system через bindep ориентирован на dnf/microdnf. Базовые образы на Debian, Ubuntu или Alpine официально не поддерживаются - не пытайся собрать EE поверх ubuntu:22.04.
- Забыл питон-зависимость. Коллекция установилась, а модуль падает с "No module named jmespath". Коллекции из Galaxy НЕ тянут pip-зависимости автоматически - их надо явно прописать в requirements.txt.
- Путаешь build и create. create только генерирует Containerfile, образа не будет. Чтобы получить образ - build.
- Кеш слоёв. Поменял requirements.yml, а версия коллекции старая - podman взял слой из кеша. Пересобирай с --no-cache, если зависимости явно обновились, а образ это игнорирует.
Повтори руками, без копипасты целиком:
- Поставь ansible-builder через pip и проверь версию.
- Создай каталог проекта и четыре файла: execution-environment.yml (version 3), requirements.yml с ansible.posix и community.general, requirements.txt с jmespath, bindep.txt с gcc и git-core.
- Собери образ: ansible-builder build -t myee:1.0 -v 3.
- Загляни в сгенерированный context/Containerfile - найди, на каком шаге ставятся коллекции и где врезались твои additional_build_steps.
- Проверь содержимое: podman run --rm myee:1.0 ansible-galaxy collection list.
- Запусти любой простой плейбук через ansible-navigator с этим образом.
- Какие три слоя зависимостей описываются в dependencies и на какие файлы они ссылаются по умолчанию?
- Чем отличается ansible-builder create от ansible-builder build?
- Почему модуль из community.general может упасть с ошибкой про отсутствующий питон-модуль, даже если коллекция установилась?
- В какие точки additional_build_steps можно врезать свои команды и зачем нужен prepend_final?
ansible-builder превращает декларативный execution-environment.yml (version 3) в воспроизводимый контейнер: три слоя зависимостей (galaxy, python, system), генерация Containerfile и сборка через podman одной командой build. Это уже не экзотика, а базовый навык современного RHCE: ansible-navigator и Automation Platform работают именно с EE-образами. Соберёшь свой EE с ansible.posix и community.general руками - и проблема "а у меня другой ansible" уходит навсегда.