AAP 2.6 Execution Environments: Build, Manage, and Deploy Custom EEs
By Luca Berton · Published 2024-01-01 · Category: installation
Complete guide to Execution Environments in AAP 2.6. Build custom EEs with ansible-builder, manage images in Private Automation Hub, troubleshoot dependency.
What Are Execution Environments?
Execution Environments (EEs) are container images that package everything needed to run Ansible automation in a consistent, portable, and isolated way: • Ansible Core runtime • Python packages required by collections and custom modules • System packages (libraries, binaries) • Ansible Collections pre-installed • Custom plugins and filter plugins
EEs replace the legacy approach of managing Python virtual environments and system dependencies directly on control nodes. In AAP 2.6, all automation runs inside EEs — on both Automation Controller and locally with ansible-navigator.
See also: Ansible Execution Environments: Build Custom EEs for Enterprise Automation
Why EEs Solve Real Problems
Before EEs (The Pain)
Control Node
├── Python 3.9 virtualenv (for network team)
│ ├── paramiko 2.x
│ ├── netmiko 4.x
│ └── cisco.ios collection
├── Python 3.11 virtualenv (for cloud team)
│ ├── boto3 1.x
│ ├── azure-mgmt-compute
│ └── amazon.aws collection
└── System packages: libxml2, libxslt, openssl
└── Version conflicts between teams!
With EEs (The Solution)
ee-network:1.0 ee-cloud:1.0 ee-security:1.0
├── Python 3.11 ├── Python 3.11 ├── Python 3.11
├── paramiko 3.x ├── boto3 1.x ├── python-nmap
├── netmiko 4.x ├── azure-mgmt-* ├── openscap
├── cisco.ios ├── amazon.aws ├── ansible.posix
└── Isolated! └── Isolated! └── Isolated!
Each team gets their own container image with exactly the dependencies they need. No conflicts, no drift, completely reproducible.
Red Hat Provided EE Images
AAP 2.6 ships with base images from the Red Hat registry:
| Image | Contents | Use Case |
|-------|----------|----------|
| ee-minimal-rhel9 | Ansible Core + minimal Python deps | Lightweight tasks, custom base |
| ee-supported-rhel9 | Core + Red Hat certified collections | General enterprise automation |
| ee-29-rhel9 | Core 2.16 + latest supported collections | Latest features and modules |
Pull from the Red Hat registry:
podman login registry.redhat.io
podman pull registry.redhat.io/ansible-automation-platform-26/ee-supported-rhel9:latest
See also: Ansible Builder & Execution Environments: Complete Guide (2026)
Building Custom EEs with ansible-builder
Install ansible-builder
pip install ansible-builder
Execution Environment Definition (v3)
Create execution-environment.yml:
---
version: 3
images:
base_image:
name: registry.redhat.io/ansible-automation-platform-26/ee-minimal-rhel9:latest
dependencies:
galaxy:
collections:
- name: cisco.ios
version: ">=9.0.0"
- name: cisco.nxos
version: ">=9.0.0"
- name: ansible.netcommon
version: ">=7.0.0"
- name: ansible.utils
version: ">=5.0.0"
python:
- paramiko>=3.0
- netmiko>=4.0
- textfsm>=1.1
- ntc-templates>=6.0
- jmespath>=1.0
system:
- openssh-clients [platform:rpm]
- iputils [platform:rpm]
- bind-utils [platform:rpm]
additional_build_steps:
prepend_base:
- RUN whoami
- RUN cat /etc/os-release
append_final:
- RUN pip3 freeze | grep -i ansible
- RUN ansible-galaxy collection list
Build the Image
# Build with Podman (default)
ansible-builder build \
--tag registry.example.com/ee-network:1.0 \
--container-runtime podman \
--prune-images
# Build with Docker
ansible-builder build \
--tag registry.example.com/ee-network:1.0 \
--container-runtime docker
Build Output
Running command:
podman build -f context/Containerfile -t registry.example.com/ee-network:1.0 context
Step 1/14 : FROM registry.redhat.io/ansible-automation-platform-26/ee-minimal-rhel9:latest
Step 2/14 : RUN whoami
---> runner
Step 3/14 : RUN pip3 install paramiko>=3.0 netmiko>=4.0 textfsm>=1.1 ...
Step 4/14 : RUN ansible-galaxy collection install cisco.ios>=9.0.0 ...
...
Complete! The build context can be found at: context
EE Definition Deep Dive
Galaxy Dependencies (Collections)
Specify collections with version constraints:
dependencies:
galaxy:
collections:
- name: amazon.aws
version: ">=9.0.0,<10.0.0"
- name: community.aws
version: ">=9.0.0"
- name: amazon.cloud
# Git source for unreleased collections
- name: custom.internal
source: https://github.com/myorg/ansible-custom-collection
type: git
version: main
Or reference a requirements.yml file:
dependencies:
galaxy: requirements.yml
Python Dependencies
Specify Python packages:
dependencies:
python:
- boto3>=1.34
- botocore>=1.34
- jmespath>=1.0
- netaddr>=1.0
Or reference a requirements.txt file:
dependencies:
python: requirements.txt
System Dependencies
Use Bindep format for system packages:
dependencies:
system:
- gcc [platform:rpm compile]
- python3-devel [platform:rpm compile]
- libxml2-devel [platform:rpm]
- libxslt-devel [platform:rpm]
- openssl-devel [platform:rpm]
- krb5-libs [platform:rpm]
- krb5-devel [platform:rpm]
Additional Build Steps
Inject custom Containerfile instructions:
additional_build_steps:
prepend_base:
- ENV MY_VAR=production
- RUN mkdir -p /opt/custom/plugins
prepend_galaxy:
- COPY ansible.cfg /etc/ansible/ansible.cfg
prepend_builder:
- RUN pip3 install --upgrade pip
prepend_final:
- RUN mkdir -p /opt/app/data
append_final:
- COPY custom_filter_plugins/ /usr/share/ansible/plugins/filter/
- COPY custom_modules/ /usr/share/ansible/plugins/modules/
- RUN ansible --version
- LABEL maintainer="platform-team@example.com"
- LABEL version="1.0"
See also: Ansible Automation Platform 2.6 Architecture and Components: Complete Guide
Publishing EEs to Private Automation Hub
Push your custom EE to Private Automation Hub for use across your organization:
# Tag the image for your Hub registry
podman tag registry.example.com/ee-network:1.0 \
hub.example.com/ee-network:1.0
# Login to Private Automation Hub
podman login hub.example.com
# Push the image
podman push hub.example.com/ee-network:1.0
Configure Controller to Use Custom EE
- name: Register custom EE in Controller
ansible.platform.execution_environment:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Network Automation EE"
image: "hub.example.com/ee-network:1.0"
pull: "missing" # missing, always, or never
description: "Custom EE for Cisco/Arista network automation"
state: present
- name: Assign EE to job template
ansible.platform.job_template:
controller_host: "{{ gateway_url }}"
controller_username: "{{ controller_user }}"
controller_password: "{{ controller_pass }}"
name: "Network Configuration Backup"
execution_environment: "Network Automation EE"
state: present
Testing EEs Locally with ansible-navigator
Before pushing to production, test your EE locally:
# Run a playbook inside the custom EE
ansible-navigator run playbook.yml \
--eei registry.example.com/ee-network:1.0 \
--mode stdout
# Interactive mode — explore the EE
ansible-navigator --eei registry.example.com/ee-network:1.0
# List collections inside the EE
ansible-navigator collections \
--eei registry.example.com/ee-network:1.0
# Check installed Python packages
ansible-navigator exec \
--eei registry.example.com/ee-network:1.0 \
-- pip3 freeze
# Inspect EE metadata
ansible-navigator images \
--eei registry.example.com/ee-network:1.0
Multi-Stage Builds for Smaller Images
Optimize EE image size by separating build-time and runtime dependencies:
---
version: 3
images:
base_image:
name: registry.redhat.io/ansible-automation-platform-26/ee-minimal-rhel9:latest
dependencies:
galaxy:
collections:
- name: community.crypto
- name: ansible.posix
python:
- cryptography>=42.0
- pyOpenSSL>=24.0
system:
# Build-time only — install headers for compilation
- gcc [platform:rpm compile]
- python3-devel [platform:rpm compile]
- openssl-devel [platform:rpm compile]
# Runtime only — needed at execution time
- openssl [platform:rpm]
additional_build_steps:
append_final:
# Clean up build artifacts
- RUN pip3 cache purge
- RUN dnf clean all
- RUN rm -rf /var/cache/dnf /tmp/*
The [platform:rpm compile] tag tells ansible-builder to install these packages only during the build stage and remove them from the final image.
Versioning and CI/CD for EEs
Automated EE Build Pipeline
# .github/workflows/build-ee.yml
name: Build Execution Environment
on:
push:
paths:
- 'execution-environments/**'
branches: [main]
schedule:
- cron: '0 6 * * 1' # Weekly Monday 6 AM
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
ee: [ee-network, ee-cloud, ee-security]
steps:
- uses: actions/checkout@v4
- name: Install ansible-builder
run: pip install ansible-builder
- name: Build EE
run: |
cd execution-environments/${{ matrix.ee }}
ansible-builder build \
--tag hub.example.com/${{ matrix.ee }}:${{ github.sha }} \
--tag hub.example.com/${{ matrix.ee }}:latest
- name: Push to Hub
run: |
podman login hub.example.com -u ${{ secrets.HUB_USER }} -p ${{ secrets.HUB_PASS }}
podman push hub.example.com/${{ matrix.ee }}:${{ github.sha }}
podman push hub.example.com/${{ matrix.ee }}:latest
Semantic Versioning for EEs
# Tag with semantic versions
podman tag ee-network:latest hub.example.com/ee-network:2.1.0
podman tag ee-network:latest hub.example.com/ee-network:2.1
podman tag ee-network:latest hub.example.com/ee-network:2
# Push all tags
podman push hub.example.com/ee-network:2.1.0
podman push hub.example.com/ee-network:2.1
podman push hub.example.com/ee-network:2
Troubleshooting
Collection Dependency Conflicts
ERROR: Cannot install ansible.netcommon>=7.0.0 and ansible.utils>=4.0.0
because these package versions have conflicting dependencies.
Fix: Pin compatible versions explicitly:
dependencies:
galaxy:
collections:
- name: ansible.netcommon
version: "7.1.0"
- name: ansible.utils
version: "5.0.0"
Python Package Build Failures
error: command 'gcc' not found
Fix: Add build-time system dependencies:
dependencies:
system:
- gcc [platform:rpm compile]
- python3-devel [platform:rpm compile]
Image Too Large
# Check image size
podman images | grep ee-network
# ee-network 1.0 abc123 1.2 GB
# Reduce size:
# 1. Use ee-minimal instead of ee-supported as base
# 2. Add cleanup steps in additional_build_steps
# 3. Remove unnecessary collections
# 4. Use multi-stage builds with compile tags
Authentication to Red Hat Registry
Error: unauthorized: access to the requested resource is not authorized
Fix: Login to the Red Hat registry with your RHN credentials:
podman login registry.redhat.io
# Username: your-rhn-username
# Password: your-rhn-password
FAQ
Can I use community base images instead of Red Hat?
Yes, but only Red Hat base images are supported under your AAP subscription. Community images like quay.io/ansible/ansible-runner work for development but are not tested or supported by Red Hat for production AAP deployments.
How often should I rebuild EEs?
Rebuild when collection versions change, Python dependencies update, or security patches are released. A weekly automated build via CI/CD is a good baseline. Always rebuild after Ansible Core security advisories.
Can I run different EEs for different job templates?
Yes. Each job template in Automation Controller can specify its own Execution Environment. This is the recommended approach — build purpose-specific EEs (network, cloud, security, Windows) rather than one monolithic image.
What is the difference between ansible-builder v2 and v3?
Version 3 of the EE definition format (used in this guide) adds support for multi-stage builds via [compile] tags, multiple base image selection, and more flexible additional_build_steps hooks. Always use version: 3 for new EEs.
Can execution nodes pull EEs from external registries?
Execution nodes pull EE images from the registry configured in Automation Controller. For air-gapped environments, use Private Automation Hub as a local registry mirror. Execution nodes must have network access to the configured registry.
Conclusion
Execution Environments are foundational to AAP 2.6's architecture. They eliminate dependency conflicts, ensure reproducibility across environments, and enable teams to independently manage their automation toolchains. Invest in a proper EE build pipeline early — it pays dividends as your automation scales.
Related Articles
• AAP 2.6 Architecture and Components: Complete Guide • AAP 2.6 RPM Deprecation and Containerized Migration • AAP 2.6 New Collections and Integrations • AAP 2.6 Configuration as Code with ansible.platform • AAP 2.6 Security Best PracticesSee also
• Ansible Builder & Execution Environments: Complete Guide (2026)Category: installation