Ansible Execution Environments: Build Custom EEs for Enterprise Automation
By Luca Berton · Published 2024-01-01 · Category: installation
How to build custom Ansible Execution Environments with ansible-builder. Package Python dependencies, collections, and system packages for consistent.
Introduction
Execution Environments (EEs) are containerized images that package everything needed to run Ansible automation: ansible-core, Python dependencies, system packages, and Ansible collections. They solve the "works on my machine" problem by ensuring consistent execution across development laptops, CI/CD pipelines, and Ansible Automation Platform.
See also: Ansible Builder & Execution Environments: Complete Guide (2026)
Why Execution Environments?
Before EEs, teams struggled with:
- Dependency conflicts — Different playbooks needing different Python library versions
- Inconsistent results — Playbook works locally but fails in AAP
- Manual setup — Each automation host needs its own dependency installation
- Security concerns — Uncontrolled Python packages on shared infrastructure
Architecture
┌─────────────────────────────────┐
│ Execution Environment │
│ │
│ ┌───────────────────────────┐ │
│ │ ansible-core 2.20 │ │
│ ├───────────────────────────┤ │
│ │ Python packages │ │
│ │ - boto3, azure-cli │ │
│ │ - hvac, netaddr │ │
│ ├───────────────────────────┤ │
│ │ System packages │ │
│ │ - openssh-clients │ │
│ │ - git, unzip │ │
│ ├───────────────────────────┤ │
│ │ Ansible collections │ │
│ │ - amazon.aws │ │
│ │ - community.general │ │
│ │ - community.docker │ │
│ └───────────────────────────┘ │
│ Base: RHEL UBI 9 Minimal │
└─────────────────────────────────┘See also: AAP 2.6 Execution Environments: Build, Manage, and Deploy Custom EEs
Install ansible-builder
pip install ansible-builder
# Verify
ansible-builder --versionDefine Your Execution Environment
Create an execution-environment.yml file:
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
ansible_core:
package_pip: ansible-core>=2.16,<2.21
ansible_runner:
package_pip: ansible-runner
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
additional_build_files:
- src: ansible.cfg
dest: configs
additional_build_steps:
prepend_galaxy:
- COPY _build/configs/ansible.cfg /etc/ansible/ansible.cfg
append_final:
- RUN chmod -R 755 /usr/share/ansiblerequirements.yml (Collections)
---
collections:
- name: amazon.aws
version: ">=8.0.0"
- name: community.general
version: ">=10.0.0"
- name: community.docker
version: ">=4.0.0"
- name: community.hashi_vault
version: ">=6.0.0"
- name: ansible.posix
- name: ansible.utilsrequirements.txt (Python)
boto3>=1.34
botocore>=1.34
hvac>=2.0
netaddr>=0.10
jmespath>=1.0
pywinrm>=0.4
requests>=2.31
cryptography>=42.0bindep.txt (System Packages)
openssh-clients [platform:redhat]
git [platform:redhat]
unzip [platform:redhat]
python3-devel [platform:redhat]
gcc [platform:redhat compile]See also: Build a Custom Ansible Execution Environment Easily
Build the EE
# Build with Podman (default)
ansible-builder build \
--tag my-org/ansible-ee:latest \
--container-runtime podman
# Build with Docker
ansible-builder build \
--tag my-org/ansible-ee:latest \
--container-runtime docker
# Build with verbose output
ansible-builder build \
--tag my-org/ansible-ee:1.0.0 \
--verbosity 3Test the EE
# Run a playbook inside the EE
ansible-runner run . \
--container-image my-org/ansible-ee:latest \
--process-isolation \
-p site.yml
# Interactive shell
podman run -it my-org/ansible-ee:latest /bin/bash
# Verify collections
podman run my-org/ansible-ee:latest \
ansible-galaxy collection list
# Verify Python packages
podman run my-org/ansible-ee:latest \
pip list | grep boto3Push to Registry
# Tag and push to private registry
podman tag my-org/ansible-ee:latest \
registry.example.com/ansible-ee:1.0.0
podman push registry.example.com/ansible-ee:1.0.0
# Push to Quay.io
podman push my-org/ansible-ee:latest \
quay.io/my-org/ansible-ee:latestUse in AAP
- Go to Administration → Execution Environments
- Click Add
- Enter:
- Name: Custom AWS EE
- Image:
registry.example.com/ansible-ee:1.0.0 - Pull: Always (recommended for mutable tags)
- Assign to Job Templates
EE for Different Use Cases
Cloud Automation EE
# requirements.yml
collections:
- amazon.aws
- azure.azcollection
- google.cloud
- community.general# requirements.txt
boto3
azure-cli-core
google-authNetwork Automation EE
collections:
- cisco.ios
- arista.eos
- junipernetworks.junos
- ansible.netcommon# requirements.txt
paramiko
ncclient
netaddr
xmltodictSecurity Automation EE
collections:
- community.hashi_vault
- community.crypto
- ansible.posix# requirements.txt
hvac
cryptography
pyOpenSSLCI/CD Pipeline for EE Builds
# .github/workflows/build-ee.yml
name: Build Execution Environment
on:
push:
paths:
- 'execution-environment.yml'
- 'requirements.*'
- 'bindep.txt'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ansible-builder
run: pip install ansible-builder
- name: Build EE
run: |
ansible-builder build \
--tag ${{ github.repository }}/ansible-ee:${{ github.sha }} \
--container-runtime docker
- name: Push to registry
run: |
echo "${{ secrets.REGISTRY_TOKEN }}" | \
docker login registry.example.com -u bot --password-stdin
docker push ${{ github.repository }}/ansible-ee:${{ github.sha }}Best Practices
- Pin versions — Use exact versions in requirements to ensure reproducible builds
- Use semantic versioning — Tag EE images with version numbers, not just
latest - Minimize image size — Only include dependencies you actually need
- Automate builds — CI/CD pipeline triggers on requirement changes
- Test before deploying — Run playbooks against the EE locally before pushing to AAP
- One EE per use case — Separate cloud, network, and security EEs rather than one mega-image
- Base on official images — Start from Red Hat's
ansible-runneroree-minimal-rhel9base - Document your EEs — README explaining what each EE contains and its intended use
Troubleshooting
"Collection not found" in AAP
The EE doesn't include the collection. Rebuild with it in requirements.yml.
Build fails on system packages
Check bindep.txt syntax and ensure packages exist for the base image's OS (RHEL UBI).
Image too large
Remove unnecessary system packages and compile-only dependencies. Use multi-stage builds.
FAQ
Can I use EEs with ansible-playbook CLI?
Yes — use ansible-navigator which supports EEs locally:
pip install ansible-navigator
ansible-navigator run site.yml --eei my-org/ansible-ee:latestEEs vs Python virtualenvs?
EEs package system dependencies too (not just Python). They're immutable, portable, and work identically everywhere. Virtualenvs only handle Python packages.
How often should I rebuild EEs?
Rebuild when: dependencies update (security patches), new collections needed, or ansible-core version changes. Monthly minimum for security updates.
Conclusion
Execution Environments are the foundation of reliable enterprise automation. By packaging all dependencies into immutable containers, you eliminate "works on my machine" issues and ensure every playbook runs consistently — from development through production.
Related Articles
Category: installation