An Ansible Execution Environment (EE) is a container image that packages Ansible Core, Python dependencies, Ansible collections, and system tools into a single portable runtime. EEs ensure your automation code runs identically whether it's on a developer's laptop, a test lab, or a production Ansible Automation Platform cluster, eliminating the "works on my machine" problem that plagues network automation teams.
When Ansible grew from a simple command-line tool to a full-blown platform, keeping automation consistent, portable, and scalable became a big deal. Enter Ansible Execution Environments (EEs). They were created to tackle exactly these challenges, especially in network automation where dependencies can get messy. For any serious network automation project, EEs help make sure your code runs the same way every time, whether you're on your laptop, in a test lab, or pushing to production.
Continue reading or use this breakdown to zero in on the aspects of Execution Environments most relevant to your Ansible network automation setup.Before EEs, Ansible just used whatever Python setup was on the control machine running the playbook. This could cause headaches:
To fix this, Ansible introduced the Execution Environment (EE) concept, a container-based runtime built on Podman or Docker, with all required collections, Python libraries, and tools baked in.
An Execution Environment is a container image used to run Ansible playbooks. It contains:
requests, netmiko)cisco.ios, junipernetworks.junos, arista.eos) and generic networking (ansible.netcommon).ip, netmiko, nmap, ping or openssh-clients etc.)These ansible execution environment images provide consistent automation runtimes that ensure your network automation code works identically regardless of where it runs. By packaging all dependencies, EEs get rid of that frustrating "but it works on my machine!" problem.
Read more: Ansible Setup Guide
Both Ansible Automation Platform (AAP) and its open-source upstream, AWX, ship with default Ansible Execution Environment images. These are usually lean, built on a Red Hat Universal Base Image (UBI). Both are hosted at Quay.io, a Red Hat container registry service.
This image includes:
netaddr, netmiko, paramiko, etc.)These defaults are a decent starting point, but honestly? For real-world, complex network automation, they're often missing the specific vendor modules (cisco.ios, anyone?), specialized libraries (pyats, ntc-templates), or custom tools you actually need. This is where building custom Execution Environments comes in.
A custom EE is an image you build tailored to your project or team. You pack it with exactly what you need, like:
cisco.ios, junipernetworks.junos, arista.eos, f5networks.f5_modules etc)ntc-templates, pyATS, netmiko, napalm,nornir)Lets see how to tailor EEs for your specific and build a custom EE using the Ansible Execution Environment builder (ansible-builder).
Create a definition file, usually execution-environment.yml. This file tells ansible-builder what to put in your EE: the base image to start from, Python requirements, Ansible Galaxy collections, and any extra build steps. Using this file means you can track your EE's configuration in Git, just like your automation code.
version: 1
build_arg_defaults:
EE_BASE_IMAGE: 'quay.io/ansible/awx-ee:latest'
EE_BUILDER_IMAGE: 'quay.io/ansible/ansible-builder:latest'
dependencies:
galaxy: requirements.yml
python: requirements.txt
additional_build_steps:
prepend: |
RUN pip3 install ntc_templates
append: |
RUN echo "Custom EE for Network Automation"
(You might also need separate requirements.txt for Python or requirements.yml for Galaxy if not defining directly in the main YAML file)
collections: - name: cisco.ios - name: junipernetworks.junos - name: arista.eos - name: f5networks.f5_modules
netmiko nornir napalm textfsm
Here's another example based on the latest ansible-builder v3:
version: 3
images:
base_image:
name: quay.io/ansible/awx-ee:latest
dependencies:
python:
- netmiko
- napalm
- pyats
system:
- iputils
- openssh-clients
galaxy:
collections:
- cisco.ios
- junipernetworks.junos
- arista.eos
- ansible.netcommon
additional_build_steps:
prepend: |
RUN pip3 install ntc_templates
append: |
RUN echo "Custom EE for Network Automation Built on $(date)"
Read more: Deep dive to Ansible Galaxy with our guide.
First, make sure you have ansible-builder and podman installed:
pip install ansible-builder sudo dnf install podman # or apt/yum depending on your OS
Now, build the image using your definition file:
ansible-builder build -f execution-environment.yml -t network-ee
This creates a local container image named localhost/network-ee:latest.
You can quickly test it locally:
podman run -it localhost/network-ee:latest ansible --version
Lets push to Red Hat's container registry service Quay.io now.
Log in to your registry:
podman login quay.io
Tag the image with your registry namespace and push it:
podman tag localhost/network-ee quay.io/<your-username>/network-ee:latest podman push quay.io/<your-username>/network-ee:latest
In the AAP or AWX web UI, go to Execution Environments under the Administration tab.
Click Add.
Fill in:
Save.
Open the desired Job Template.
Under Execution Environment, choose Network Automation EE.
Save.
Now your playbooks will run using the precise environment you built.
ansible-navigator is a command-line tool with a nice text-based UI (TUI) that's designed to work well with EEs. It makes running playbooks, exploring inventory, and browsing collections inside the EE much easier.
ansible-navigator run playbook.yml --eei quay.io/your_username/my-network-ee:latest
Explore collections available inside the EE:
ansible-navigator collections --eei quay.io/your_username/my-network-ee:latest
Look up module documentation from within the EE:
ansible-navigator doc ios_command --eei quay.io/your_username/my-network-ee:latest
Read more:
Here's a simple playbook to configure VLANs on Cisco IOS and Arista EOS devices. The custom EE makes sure the cisco.ios and arista.eos collections (and their dependencies) are present.
- name: Configure VLANs on network devices
hosts: all
gather_facts: no
tasks:
- name: Configure VLAN on Cisco IOS
cisco.ios.ios_vlans:
config:
- vlan_id: 100
name: TEST_VLAN
state: merged
when: ansible_network_os == 'cisco.ios.ios'
- name: Configure VLAN on Arista EOS
arista.eos.eos_vlans:
config:
- vlan_id: 100
name: TEST_VLAN
state: merged
when: ansible_network_os == 'arista.eos.eos'
Run this playbook with ansible-navigator using your EE:
ansible-navigator run vlan_config.yml --eei quay.io/your_username/my-network-ee:latest
Before pushing, you can jump inside your built EE image for a quick check:
podman run -it localhost/network-ee bash
Once inside, verify things are installed:
ansible --version ansible-galaxy collection list python3 -m pip list
Read more: Mastering Ansible Navigator
| Feature | Advantage |
|---|---|
| Portability | Runs the same everywhere: dev, test, prod. |
| Python Isolation | No more Python dependency clashes. Critical for network libraries. |
| Modular | Build specific EEs for different vendors, teams, or tasks. |
| Scalable | Works with AAP clusters and automation mesh for distributed network tasks. |
| Testable | Build and test EEs locally before deploying. |
| Secure | Start from hardened base images; control exactly what's included. |
If you've used Python virtual environments (venv or virtualenv) for Ansible before, you might wonder why EEs exist at all. The short answer: EEs solve problems that virtual environments can't.
| Aspect | Python Virtual Environment | Execution Environment |
|---|---|---|
| What it isolates | Python packages only | Python packages + system packages + Ansible collections + CLI tools |
| Container-based | No (runs on host OS) | Yes (Podman/Docker container) |
| System dependencies | Must install on host separately | Bundled inside the image |
| Portability | Tied to host OS and architecture | Runs anywhere containers run |
| AAP/AWX integration | Not supported (legacy mode only) | Native, required for modern AAP |
| Reproducibility | Depends on host OS state | Fully reproducible from definition file |
| Team sharing | Share requirements.txt (hope it works) | Share a container image (guaranteed to work) |
| Network automation fit | Works for simple setups | Handles complex multi-vendor dependencies cleanly |
Virtual environments only isolate Python packages, they can't bundle system-level tools like openssh-clients or vendor CLI utilities that network automation often needs. EEs wrap everything into a container, so the runtime is identical no matter where it executes.
If you're running Ansible from the CLI on a single machine for simple tasks, a virtual environment still works fine. But the moment you need consistency across a team, CI/CD pipelines, or AAP/AWX, EEs are the right tool.
EEs make it easier to use other advanced Ansible features for networking:
ansible.netcommon have modules (cli_command, cli_config) that work across different vendors. EEs ensure these collections are always available.paramiko, requests) needed by connection plugins (network_cli, httpapi) and modules (netmiko) for solid SSH/API communication.network_cli, httpapi) that handle device quirks (prompts, timeouts) better than raw SSH/API calls.textfsm and libraries like ntc-templates in your EE to parse unstructured CLI output into usable JSON – vital for automating older gear.execution-environment.yml and related files in Git. Tag your EE image builds alongside your code releases.Read more: How you write and structure your Ansible playbooks totally impacts how well they scale. Read our article on the best practices for Ansible playbooks.
Execution Environments are a big step forward for doing network automation properly with Ansible. They bring consistency and solve dependency headaches, letting network engineers build, test, and roll out automation more reliably, no matter the environment or scale.
While powerful, building and managing EEs takes some effort. CloudMyLab offers services to help:
Ansible Instant Env: Get pre-configured EEs, ready to go quickly, avoiding setup hassles. We have pre-built EEs optimized for Cisco, Juniper, Fortinet, etc.
Realistic Testing: Test your own custom EEs in complex network labs using our Lab as a Service (EVE-NG Pro, Cisco CML). Validate everything safely before it hits production.
Expert Help: Our Professional Services team can help design and build custom EEs tailored exactly to your network and automation goals.
Why risk breaking production with untested automation? Use CloudMyLab's sandbox environments to test with confidence.
Check out our Ansible Network Automation offerings or start a free trial.
Here are some helpful resources for learning more about Ansible:
The Ansible Automation Platform Execution Environment (EE) is the official container runtime from Red Hat for AAP. It bundles Ansible, certified content, and dependencies for consistent execution within AAP.
The Ansible AWX Execution Environment (EE) is the container image used by the open-source AWX project (upstream for AAP controller). Usually found at quay.io/ansible/awx-ee, it provides the runtime for jobs managed by AWX.
Ansible-navigator is a command-line tool (with a text UI) made for working with Ansible, especially EEs. It handles running playbooks inside an EE container for you. Use the --eei <image_name> flag to specify which EE to use.
Ansible execution environment images are container images packaging Ansible and everything needed to run playbooks consistently. Official ones are on registries like Red Hat Automation Hub or Quay.io. You build custom ones and store them in your preferred registry. CloudMyLab also offers pre-built, network-focused EEs via services like Ansible Instant Env.
You need a container runtime, either Podman or Docker. Red Hat recommends Podman since it's rootless by default and doesn't require a daemon. The ansible-builder tool uses your container runtime to build EE images, and ansible-navigator uses it to run playbooks inside those images. If you're on RHEL or Fedora, Podman is pre-installed. On Ubuntu or macOS, you can install either one.
Yes. You don't need AAP or AWX to use EEs. The ansible-navigator command-line tool can run playbooks inside EE containers directly on your local machine. This is useful for local development, testing, and CI/CD pipelines. AAP and AWX just add the web UI, scheduling, and role-based access control on top.
Update the execution-environment.yml definition file (or the linked requirements.txt / requirements.yml), then rebuild with ansible-builder build. Tag the new image with a version number (e.g., network-ee:2.1) and push it to your registry. In AAP/AWX, update the Execution Environment entry to point to the new tag. Always test the updated EE against staging devices before switching production job templates to use it.
They handle different parts of the workflow. ansible-builder creates Execution Environment container images. It is a build tool you use once to package your dependencies. ansible-runner executes Ansible playbooks inside those containers. It is the runtime component that AAP, AWX, and ansible-navigator use under the hood to actually run your automation jobs.