
Construire son propre EE est l'étape qui sépare un consommateur d'un opérateur Ansible 2026. Avec ansible-builder v3.1+ et un fichier execution-environment.yml au schéma v3, on assemble une image OCI custom : ansible-core pinné, collections Galaxy pinnées, dépendances Python pinnées, packages système pinnés. Le résultat est une image bit-pour-bit reproductible, pushée sur registre privé, signée, consommée par AAP, ansible-navigator, ou la CI/CD.
À la fin, vous saurez écrire un execution-environment.yml v3 propre, builder via Podman avec ansible-builder build, inspecter le Containerfile multi-stage généré, et tester l'EE construit.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Schéma
version: 3: sectionsimages,dependencies,additional_build_files,additional_build_steps. - Pinning rigoureux : ansible-core, collections, Python, system.
ansible-builder buildavec Podman.- Multi-stage Containerfile généré (4 stages : base, galaxy, builder, final).
- Smoke tests post-build pour valider l'image.
- Pièges courants v3.
Prérequis
Section intitulée « Prérequis »- Avoir lu Modes interactifs et Inspecter un EE.
ansible-builder ≥ 3.1.0(pipx install ansible-builder).- Podman installé.
Anatomie d'un projet EE
Section intitulée « Anatomie d'un projet EE »mon-ee/├── execution-environment.yml ← recette principale├── requirements.yml ← collections Galaxy├── requirements.txt ← deps Python (pip)├── bindep.txt ← deps système (dnf/apt)├── configs/│ └── ansible.cfg ← (optionnel) config injectée└── context/ ← (généré par ansible-builder) ├── Containerfile └── _build/ ├── requirements.yml ├── requirements.txt └── bindep.txtQuatre fichiers d'entrée que vous écrivez, plus le context/ généré par ansible-builder. Versionnez les 4 fichiers + ignorez context/ (généré à chaque build).
Le fichier execution-environment.yml v3
Section intitulée « Le fichier execution-environment.yml v3 »---version: 3 # OBLIGATOIRE en 2026
images: base_image: name: ghcr.io/ansible-community/community-ee-minimal:latest
dependencies: ansible_core: package_pip: ansible-core==2.18.1 ansible_runner: package_pip: ansible-runner==2.4.1 galaxy: requirements.yml python: requirements.txt system: bindep.txt python_interpreter: package_system: python3.11 python_path: /usr/bin/python3.11
additional_build_files: - src: configs/ansible.cfg dest: configs
additional_build_steps: prepend_base: - RUN echo "Build $(date)" > /etc/ee-build-info append_final: - COPY _build/configs/ansible.cfg /etc/ansible/ansible.cfg - RUN chmod 0644 /etc/ansible/ansible.cfgimages.base_image.name
Section intitulée « images.base_image.name »L'image point de départ. Choix typiques :
| Base | Cas d'usage |
|---|---|
ghcr.io/ansible-community/community-ee-minimal:latest | EE custom léger (~400 MB de base) |
ghcr.io/ansible-community/community-ee-base:latest | EE custom avec quelques collections de base |
registry.redhat.io/.../ee-minimal-rhel9 | Production AAP entreprise |
Bonne pratique : pinner par digest SHA-256 plutôt que par tag mutable :
base_image: name: ghcr.io/ansible-community/community-ee-minimal:2.21.3-1@sha256:4359b29750dfc67b55e73bfc5a4ffa804c882c1376a33e59217c1087632241e6Empêche un repush silencieux upstream de modifier votre base. La forme
canonique porte le tag et le digest : le tag reste lisible par un humain,
le digest est ce qui est réellement tiré. Relevez-le une fois, avec
skopeo inspect --format '{{.Digest}}' docker://<image>:<tag>, puis
rafraîchissez-le à chaque montée de version : un digest ne reçoit aucun
correctif de sécurité, c'est la contrepartie assumée de l'épinglage.
dependencies.ansible_core et ansible_runner
Section intitulée « dependencies.ansible_core et ansible_runner »ansible_core: package_pip: ansible-core==2.18.1ansible_runner: package_pip: ansible-runner==2.4.1Pinning strict avec ==. Sans cette section ou sans pin, vous récupérez la dernière version au moment du build → reproductibilité cassée.
dependencies.galaxy
Section intitulée « dependencies.galaxy »Pointe sur requirements.yml :
collections: - name: ansible.posix version: 2.0.0 - name: community.general version: 10.5.0 - name: kubernetes.core version: 5.1.1Pinner toutes les versions. Une collection sans version → dernière au build, drift garanti à terme.
dependencies.python
Section intitulée « dependencies.python »Pointe sur requirements.txt :
kubernetes==31.0.0PyYAML==6.0.2jsonpatch==1.33Format pip standard. Toujours ==, jamais >=.
dependencies.system
Section intitulée « dependencies.system »Pointe sur bindep.txt :
git [platform:rpm]openssh-clients [platform:rpm]sshpass [platform:rpm]Format bindep : nom du paquet + profil. [platform:rpm] pour les bases UBI/RHEL/AlmaLinux ; [platform:dpkg] pour Ubuntu base.
additional_build_files
Section intitulée « additional_build_files »Fichiers supplémentaires à copier dans le contexte de build :
additional_build_files: - src: configs/ansible.cfg dest: configssrc est relatif au répertoire du execution-environment.yml, dest est relatif au _build/ dans le context/. Utilisé pour des configs, certificats CA, scripts.
additional_build_steps
Section intitulée « additional_build_steps »Lignes Containerfile injectées à des moments précis :
| Hook | Quand |
|---|---|
prepend_base | Tout début du stage base |
append_base | Fin du stage base |
prepend_galaxy | Avant ansible-galaxy collection install |
append_galaxy | Après l'install Galaxy |
prepend_final | Début du stage final |
append_final | Fin du stage final (juste avant le tag) |
Cas d'usage : injecter une config, un certificat CA d'entreprise, un script d'initialisation, un label OCI.
Le build avec ansible-builder
Section intitulée « Le build avec ansible-builder »ansible-builder build \ --tag localhost/my-ee:1.0.0 \ --container-runtime podman \ --file execution-environment.yml \ --context ./context \ --verbosity 2Options clés :
--tag: nom + tag de l'image résultat. Toujours semver (:1.0.0), jamais:latesten CI.--container-runtime:podman(recommandé 2026) oudocker.--file: fichier de définition (default :execution-environment.yml).--context: où ansible-builder écrit leContainerfilegénéré.--verbosity:0à3.2recommandé en CI pour capter les warnings.--no-cache: forcer rebuild complet (debug, ou changement de requirements caché).
Le Containerfile multi-stage généré
Section intitulée « Le Containerfile multi-stage généré »# context/Containerfile (extrait simplifié, écrit par ansible-builder)ARG EE_BASE_IMAGE="ghcr.io/ansible-community/community-ee-minimal:latest"# ... (les autres ARG et options posés par ansible-builder sont omis ici)
FROM $EE_BASE_IMAGE AS baseRUN echo "Build $(date)" > /etc/ee-build-infoCOPY _build/bindep.txt /tmp/src/bindep.txtRUN microdnf install -y --nodocs \ $(grep '\[platform:rpm\]' /tmp/src/bindep.txt | awk '{print $1}')
FROM base AS galaxyCOPY _build/requirements.yml /tmp/requirements.ymlRUN ansible-galaxy collection install -r /tmp/requirements.yml \ --collections-path "/usr/share/ansible/collections"
FROM base AS builderCOPY _build/requirements.txt /tmp/src/requirements.txtRUN pip install --no-cache-dir -r /tmp/src/requirements.txt
FROM base AS finalCOPY --from=galaxy /usr/share/ansible/collections /usr/share/ansible/collectionsCOPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packagesCOPY _build/configs/ansible.cfg /etc/ansible/ansible.cfgRUN chmod 0644 /etc/ansible/ansible.cfg4 stages : base, galaxy, builder, final. Le stage final ne contient que ce qui sert au runtime (pas les compilers Python, par exemple, qui ont servi à compiler les wheels).
Smoke tests post-build
Section intitulée « Smoke tests post-build »Toujours valider l'image après le build :
# 1. ansible-core présent ?podman run --rm localhost/my-ee:1.0.0 ansible --version | head -1# Attendu : ansible [core 2.18.1]
# 2. Collections présentes ?podman run --rm localhost/my-ee:1.0.0 ansible-galaxy collection list
# 3. Module spécifique disponible ?podman run --rm localhost/my-ee:1.0.0 ansible-doc kubernetes.core.k8s | head -3
# 4. Python version ?podman run --rm localhost/my-ee:1.0.0 python3 --versionCritique : sans smoke tests, un EE peut « builder sans erreur » et pourtant ne pas contenir ansible-core, cas du version: 3 manquant détaillé dans Déboguer un EE cassé. Le smoke test attrape ce cas immédiatement.
Pièges courants v3
Section intitulée « Pièges courants v3 »version: 3oublié → ansible-builder lit en mode v1, ignore les sections de deps modernes.- Collection inexistante dans
requirements.yml→ansible-galaxy installéchoue mais erreur peut être noyée si verbosity basse. - Version PyPI inexistante →
pip install kubernetes==9999échoue, messageNo matching distribution. - Profil
[platform:rpm]manquant dansbindep.txt→ tous les paquets ignorés sur base UBI. - Cache Podman : modifier
requirements.ymlne déclenche pas toujours rebuild de la couche galaxy →--no-cacheou bumper une variable dansprepend_galaxy.
Mettre en pratique
Section intitulée « Mettre en pratique »Un execution-environment.yml syntaxiquement correct ne garantit pas un environnement utilisable : seul le contrôle de l'artefact construit le dit. Le lab vous fait écrire les quatre fichiers d'entrée en schéma v3, épingler ansible-core ainsi que chaque collection et chaque dépendance PyPI, builder avec Podman, puis publier le résultat sur un registre. Les tests portent précisément sur l'épinglage : une version flottante restée quelque part fait échouer la validation.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »version: 3obligatoire dansexecution-environment.yml.- Pinner tout : ansible-core, collections, Python deps, system deps.
- 4 fichiers d'entrée :
execution-environment.yml,requirements.yml,requirements.txt,bindep.txt. - Multi-stage Containerfile généré :
base,galaxy,builder,final. - Smoke tests post-build :
podman run --rm $TAG ansible --version. - Tag semver :
:1.0.0, jamais:latesten CI.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Debug d'un EE cassé : Les quatre bugs d'ansible-builder v3 qui produisent un build vert et une image inutilisable.
- requirements.yml multi-sources : Le fichier de collections embarqué dans l'EE, avec pinning semver et signatures détachées.
- Créer une collection custom : Empaqueter votre propre code pour l'embarquer dans l'image au lieu de le monter en volume.