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
EEs solve all of these by packaging dependencies into immutable container images.
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 --version
Define 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/ansible
requirements.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.utils
requirements.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.0
bindep.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 3
Test 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 boto3
Push 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:latest
Use 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-auth
Network Automation EE
collections:
- cisco.ios
- arista.eos
- junipernetworks.junos
- ansible.netcommon
# requirements.txt
paramiko
ncclient
netaddr
xmltodict
Security Automation EE
collections:
- community.hashi_vault
- community.crypto
- ansible.posix
# requirements.txt
hvac
cryptography
pyOpenSSL
CI/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 justlatest
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-runner or ee-minimal-rhel9 base
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:latest
EEs 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
• Ansible Automation Platform 2.6 • Ansible Docker Complete Guide • What is Ansible AWX?Category: installation