In Ansible, an execution environment is a container image that includes all the necessary dependencies, modules, and plugins needed to run automation tasks.
With Ansible Builder, you can build and customize these images, ensuring consistent and reproducible execution of playbooks and roles in a known environment.
Prerequisites
You should have the following installed on your system:
- Either Podman or Docker
- Python
- pip
Installation
We will install using pip, the Python package manager.
We will install it in a Python virtual environment to isolate the installation and prevent potential conflicts with system packages.
Create and activate a virtual environment:
$ python3 -m venv venv
$ source venv/bin/activate # On Windows: venv\Scripts\activate
$ pip install ansible-builder
Building an Execution Environment for Proxmox
Creating the Build Files
Let’s use Ansible Builder to build an execution environment for managing Proxmox servers. Proxmox VE is an open-source virtualization platform similar to VMware vSphere.
While you can include various files in your execution environment build, the core file is execution-environment.yml.
---
version: 3
images:
base_image:
name: quay.io/ansible/awx-ee:latest
dependencies:
ansible_core:
package_pip: ansible-core==2.14.0
ansible_runner:
package_pip: ansible-runner
galaxy:
collections:
- community.general
python:
- proxmoxer
- requests
system:
- gcc
- python3-devel
- libxml2-devel
additional_build_files:
- src: ansible.cfg
dest: configs
additional_build_steps:
prepend_final:
- ADD _build/configs/ansible.cfg /etc/ansible/ansible.cfg
options:
package_manager_path: /usr/bin/dnf
ansible-core==2.14.0 as an example. You should check the Ansible documentation for the current supported release and update accordingly.The above execution-environment.yml has all the Ansible, Python, and system requirements in line.
You can also specify them as separate files, such as requirements.yml (Ansible) and requirements.txt (Python).
--snip--
dependencies:
ansible_core:
package_pip: ansible-core==2.14.0
ansible_runner:
package_pip: ansible-runner
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
--snip--
I have included an empty ansible.cfg here to show how you include it in your image build.
Feel free to put any options in this file that you want to use in your execution environment.
Our execution-environment.yml will put this in the container image where we specify.
We will look more at this later on.
microdnf as the package manager explicitly (it handles some RPM installs even if you don’t request extra packages). In the current version, the build looks for microdnf by default, but awx-ee now includes dnf. Because of this, I had to adjust the steps above to get everything working again. I’m calling this out since these details may continue to change in future releases.When the files are ready, execute the following command:
ansible-builder build -t proxmox-env
-t tags the image that is created.
This is the message I see when running it:
Running command:
podman build -f context/Containerfile -t promox-env context
Complete! The build context can be found at: /home/pmartin/ansible-builder/article/context
Verifying the Build
After the build process finishes you should have the image available to use.
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/proxmox-env latest 0ce7182e8bab 4 minutes ago 1.58 GB
---snip---
Let’s look at the collections using podman.
$ podman run localhost/proxmox-env ansible-galaxy collection list
# /usr/share/ansible/collections/ansible_collections
Collection Version
----------------------- -------
amazon.aws 9.4.0
ansible.posix 2.0.0
ansible.windows 2.8.0
awx.awx 24.6.1
azure.azcollection 3.3.1
community.general 11.2.1
community.vmware 5.5.0
google.cloud 1.5.1
kubernetes.core 5.2.0
kubevirt.core 2.1.0
openstack.cloud 2.4.1
ovirt.ovirt 3.2.0
redhatinsights.insights 1.3.0
theforeman.foreman 5.3.0
vmware.vmware 1.11.0
For comparison this is a list of the collections that were already in the container we used as a base image.
$ podman run quay.io/ansible/awx-ee ansible-galaxy collection list
# /usr/share/ansible/collections/ansible_collections
Collection Version
----------------------- -------
amazon.aws 9.4.0
ansible.posix 2.0.0
ansible.windows 2.8.0
awx.awx 24.6.1
azure.azcollection 3.3.1
community.vmware 5.5.0
google.cloud 1.5.1
kubernetes.core 5.2.0
kubevirt.core 2.1.0
openstack.cloud 2.4.1
ovirt.ovirt 3.2.0
redhatinsights.insights 1.3.0
theforeman.foreman 5.3.0
vmware.vmware 1.11.0
The base image included a lot of collections already. But for our custom execution environment, it needed the ‘community.general’ collection, which contains the proxmox module.
Using our Execution Environment
We have the collection we need for working with proxmox, now, let’s test it. We will be using ansible-navigator to execute the playbook using our execution environment. A future article will go deeper into ansible-navigator.
This is the simple playbook we will be running.
---
- hosts: localhost
connection: local
vars_files:
- vault.yml
tasks:
- name: Create vms from a list
community.general.proxmox_kvm:
api_user: "{{ api_user }}"
api_password: "{{ api_password }}"
api_host: "{{ api_host }}"
validate_certs: false
clone: rh8-tmplt
name: prox-ee-test
node: pve
storage: Local_lun
timeout: 300
Here is the playbook run.
ansible-navigator run --eei localhost/proxmox-env clone_vm_proxmox.yml --pp=never -m stdout -i inventory
PLAY [localhost] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create vms from a list] **************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
For more details on ansible-navigator, check out this post.
| Option | Description |
|---|---|
| run | Runs a playbook |
| –eei | What execution environment image to use |
| –pp | Pull policy, whether or not to pull the image |
| -m | Output mode, stdout disables the interactive TUI |
| -i | Inventory file or host pattern to use |
After the playbook run if we check proxmox we see our vm.

New VM
It works! Now we can share that execution environment with others and know that everyone is working in the same environment. Now let’s go back and check one last thing.
When we ran the build command with ansible-builder it creates a directory, context, where it stores files used in the build.
context
├── _build
│ ├── bindep.txt
│ ├── configs
│ │ └── ansible.cfg
│ ├── requirements.txt
│ ├── requirements.yml
│ └── scripts
│ ├── assemble
│ ├── check_ansible
│ ├── check_galaxy
│ ├── entrypoint
│ ├── install-from-bindep
│ ├── introspect.py
│ └── pip_install
└── Containerfile
Some interesting files are the two requirement files and the bindep.txt - they contain exactly what you’d expect: Python modules, collections list, and system package list. You will also see our ansible.cfg has been copied into the _build directory along with a generated Containerfile that handles the actual creation of the image.
Take some time to explore these copied and generated files - they reveal how ansible-builder translates your files into a working container image.
Ansible Builder is a tool for creating your own execution environments. By leveraging its capabilities to bundle dependencies, modules, and plugins, you can ensure consistent and reliable execution of your automation workflows. This article scratches the surface of what you can do. Be sure to check out the documentation for more options.