Building Ansible Execution Environment Images
The construction of Ansible’s execution environment is essentially the construction of a container image, with Ansible providing a command <span>ansible-builder</span> to achieve standardized image building.
<span>ansible-builder</span> will by default use the <span>execution-environment.yaml</span> or <span>execution-environment.yml</span> in the current directory as the execution environment definition file (which is the <span>Containerfile</span> or <span>Dockerfile</span>).
Configuration of the Execution Environment Definition File
Ansible Builder 3.x supports 7 top-level configuration sections in the Execution Environment Definition File:
| Top-level Field Name | Description |
<span>additional_build_files</span> |
Specifies additional files to be added to the <span>_build/</span> context directory during the build process |
<span>additional_build_steps</span> |
Specifies custom commands to be inserted at different build stages (base, builder, final), such as <span>RUN</span>, <span>COPY</span>, etc. |
<span>build_arg_defaults</span> |
Sets default parameters passed to the container engine build command (e.g., <span>docker build</span>), equivalent to <span>--build-arg</span> |
<span>dependencies</span> |
Specifies required dependencies, such as Python, system packages, Ansible collections, etc. |
<span>images</span> |
Defines the base image and builder image |
<span>options</span> |
Sets additional options for build behavior, such as whether to retain cache, intermediate build directories, etc. |
<span>version</span> |
Defines the file format version, currently <span>3</span> |
Function of additional_build_files
This field is used to add custom files or directories to the build context directory for subsequent build steps (such as <span>RUN</span>, <span>COPY</span>) to reference or copy.
additional_build_files:
- src: <source_path>
dest: <target_subpath>
<span>src</span>:Source Path
- • Supports:
- • Relative Paths (relative to the
<span>execution-environment.yml</span>file) - • Absolute Paths (wildcards not supported)
- • Wildcard globs (only for relative paths)
- • Directories (the entire directory will be copied)
- • Example:
<span>files/ansible.cfg</span>or<span>/home/user/.ansible.cfg</span>
<span>dest</span>:Target Subpath (relative to the build context’s <span>_build/</span>)
- • Cannot be an absolute path
- • Cannot contain
<span>..</span> - • If the directory does not exist, it will be created automatically
- • Example:
<span>files/configs</span>,<span>custom/ansible</span>, etc.
Commonly used in conjunction with
<span>additional_build_steps</span><code><span>.</span>
Function of additional_build_steps
- • Insert custom commands at various stages of building the execution environment image
- • Allows flexible control over the build process, such as installing additional dependencies, copying files, setting environment variables, etc.
| Keyword | Insertion Position | Typical Use |
<span>prepend_base</span> |
Before the base image build starts | Install dependencies, add source configurations |
<span>append_base</span> |
After the base image build is complete | Clean cache, install custom packages |
<span>prepend_galaxy</span> |
Before installing collections | Copy <span>requirements.yml</span> |
<span>append_galaxy</span> |
After installing collections | Reset permissions, clean cache |
<span>prepend_builder</span> |
Before the builder stage starts | Install internal tool packages |
<span>append_builder</span> |
After the builder stage ends | Custom Python paths, virtual environments |
<span>prepend_final</span> |
Before the final stage starts | Copy additional files, environment variables |
<span>append_final</span> |
After the final stage ends | Set ENTRYPOINT, LABEL, clean cache, etc. |
additional_build_steps:
prepend_base:
- RUN echo "Installing base deps"
- RUN dnf install -y epel-release
append_base:
- RUN dnf clean all
prepend_final: |
COPY _build/scripts/welcome.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/welcome.sh
append_final:
- RUN echo "Build complete"
This is just an example; for cache cleaning,
<span>ansible-builder</span>will do this by default.
Do not use the
<span>USER</span>instruction when building images; if you need to set a default user, use<span>options.user</span>.
Function of build_arg_defaults
Used to specify default <span>--build-arg</span> variables when building the image. These parameters will be hardcoded into the <span>Containerfile</span> or <span>Dockerfile</span>, suitable for purposes such as installing pre-release collections, controlling dependency behavior, retaining package manager cache, etc.
| Build Parameter Name | Type | Default Value | Description |
<span>ANSIBLE_GALAXY_CLI_COLLECTION_OPTS</span> |
<span>str</span> |
null | Parameters passed to <span>ansible-galaxy collection install</span> (e.g., <span>--pre</span>) |
<span>ANSIBLE_GALAXY_CLI_ROLE_OPTS</span> |
<span>str</span> |
null | Parameters passed to <span>ansible-galaxy role install</span> (e.g., <span>--no-deps</span>) |
<span>PKGMGR_PRESERVE_CACHE</span> |
<span>str</span> |
null | Controls whether the package manager cache is preserved. Optional values:<span>always</span> (do not clean), other values indicate cleaning after system dependencies are installed; setting any other value will clean the cache in the final stage; if empty, the cache will be cleaned frequently |
Function of dependencies
<span>dependencies</span> is a core field in the Ansible Builder execution environment definition file, used to define all dependencies to be installed in the final image, including:
- •
<span>ansible-core</span>and<span>ansible-runner</span> - • Python packages
- • System packages (e.g., in bindep format)
- • Ansible Collections
- • Optional dependency exclusion rules (
<span>exclude</span>)
| Field Name | Type | Description |
<span>ansible_core</span> |
<span>dict</span> |
Specifies the installation method for <span>ansible-core</span> using <span>package_pip</span>, which can be a version number, URL, or any pip-supported format |
<span>ansible_runner</span> |
<span>dict</span> |
Specifies the installation method for <span>ansible-runner</span> using <span>package_pip</span>, also supporting pip format |
<span>galaxy</span> |
<span>dict</span> / <span>str</span> / <span>list</span> |
Specifies the Ansible Collections to be installed, supporting file paths or nested dictionary structures |
<span>python</span> |
<span>str</span> / <span>list</span> |
Python dependency packages, supporting file paths or direct listing |
<span>python_interpreter</span> |
<span>dict</span> |
Sets the Python version installed by the system package manager (corresponding field <span>package_system</span>) and the Python execution path (corresponding field <span>python_path</span>) |
<span>system</span> |
<span>str</span> / <span>list</span> |
System package dependencies, using bindep format, supporting file paths or direct listing |
<span>exclude</span> |
<span>dict</span> |
Specifies Python or system dependencies to exclude from the Collections’ dependencies (supports names or regex), requires Ansible Builder ≥ 3.1 (see the example below for format) |
<span>ansible_core</span> or <span>ansible_runner</span> supported formats (using <span>ansible_core</span> as an example):
ansible_core:
package_pip: ansible-core
ansible_core:
package_pip: ansible-core==2.14.3
ansible_core:
package_pip: https://github.com/example_user/ansible/archive/refs/heads/ansible.tar.gz
Official example:
# Reference dependency files
dependencies:
python: requirements.txt
system: bindep.txt
galaxy: requirements.yml
ansible_core:
package_pip: ansible-core==2.14.2
ansible_runner:
package_pip: ansible-runner==2.3.1
python_interpreter:
package_system: "python310"
python_path: "/usr/bin/python3.10"
# Directly inline defining dependencies
dependencies:
python:
- pywinrm
system:
- iputils [platform:rpm]
galaxy:
collections:
- name: community.windows
- name: ansible.utils
version: 2.10.1
ansible_core:
package_pip: ansible-core==2.14.2
ansible_runner:
package_pip: ansible-runner==2.3.1
python_interpreter:
package_system: "python310"
python_path: "/usr/bin/python3.10"
# Exclude specified dependencies (requires v3.1+)
dependencies:
exclude:
python:
- docker
system:
- python3-Cython
all_from_collections:
- ~community\..+ # Use regex to exclude all community.* related collection dependencies
Function of images
Used to specify the base image for building the execution environment. This base image determines the operating system of the final execution environment and some pre-installed basic packages.
| Field Name | Type | Description |
<span>base_image</span> |
<span>dict</span> |
Defines the base image information, must include <span>name</span> |
Subfields:
| Subfield Name | Type | Description |
<span>name</span> |
<span>str</span> |
Image name, recommended to use the format <span>registry/namespace/image:tag</span>, for example:<span>quay.io/ansible/ansible-runner:latest</span> |
<span>signature_original_name</span> |
<span>str</span> (optional) |
When using image signature verification and adopting images from the image repository (image replication), specify the original signature name |
images:
base_image:
name: myregistry.local/ansible-runner:latest
signature_original_name: quay.io/ansible/ansible-runner:latest
Image Signature Verification
If using the Podman container runtime, you can configure signature verification policies to ensure image security.
Optional Policies
| Policy Value | Description |
<span>ignore_all</span> |
Generates a <span>policy.json</span> file, does not perform signature verification (default skips verification) |
<span>system</span> |
Uses the system’s default signature policy file (located in <span>/etc/containers/policy.json</span>, etc.) for verification |
<span>signature_required</span> |
Enforces signature verification, must configure the image signature source in <span>base_image</span>, otherwise the build fails |
Pass via CLI parameter
<span>--container-policy</span>, for example:<span>ansible-builder build --container-policy signature_required</span>.
Function of options
<span>options</span> is a collection of advanced optional settings used to control the details of behavior during the build and the final behavior of the container, such as container initialization methods, user settings, package manager paths, etc. It is suitable for users with custom image building needs.
| Field Name | Type | Default Value | Description |
<span>container_init</span> |
<span>dict</span> |
See subfields | Configuration of container ENTRYPOINT, CMD, and auxiliary tools (such as dumb-init) |
<span>package_manager_path</span> |
<span>str</span> |
<span>/usr/bin/dnf</span> |
Specifies the package manager path, such as <span>dnf</span> or <span>microdnf</span>; setting this will use this package manager to install the Python interpreter |
<span>skip_ansible_check</span> |
<span>bool</span> |
<span>false</span> |
Whether to skip ansible/runner installation checks |
<span>skip_pip_install</span> |
<span>bool</span> |
<span>false</span> |
Whether to skip pip installation (handled manually by the user) |
<span>relax_passwd_permissions</span> |
<span>bool</span> |
<span>true</span> |
Whether to allow root write permissions to <span>/etc/passwd</span><span> (supports dynamic users) (this grants the image execution user </span><code><span>GID 0</span><span> of the </span><code><span>root</span><span> group to allow modification of </span><code><span>/etc/passwd</span><span> to add users; the built image comes with a script to add users)</span> |
<span>workdir</span> |
<span>str</span> |
<span>/runner</span> |
The default working directory for processes in the container (sometimes created as the home directory for dynamically created users via <span>entrypoint</span>); if the directory does not exist, it will be automatically created and recursively granted <span>rwx</span> permissions to the root group |
<span>user</span> |
<span>str</span>/<span>int</span> |
<span>1000</span> |
The default user in the container (username or UID) |
<span>tags</span> |
<span>list</span>(<span>str</span>) |
<span>["ansible-execution-env:latest"]</span> |
The tags used for the image after a successful build |
<span>container_init</span> subfields:
| Subfield Name | Type | Default Value | Description |
<span>cmd</span> |
<span>list</span>(<span>str</span>) |
<span>["bash"]</span> |
Specifies the default command executed in the container (CMD instruction) |
<span>entrypoint</span> |
<span>list</span>(<span>str</span>) |
<span>["/opt/builder/bin/entrypoint", "dumb-init"]</span> |
The container’s ENTRYPOINT, including signal forwarding and user environment initialization; this ENTRYPOINT ensures that the user starting the container has the appropriate environment and home directory (if this user does not exist, it will attempt to create it), otherwise a warning will be issued |
<span>package_pip</span> |
<span>str</span> |
<span>dumb-init==1.2.5</span> |
Installed in the final image, used to support the ENTRYPOINT pip package |
options:
container_init:
package_pip: dumb-init>=1.2.5
entrypoint: ["dumb-init"]
cmd: ["csh"]
package_manager_path: /usr/bin/microdnf
skip_ansible_check: true
skip_pip_install: false
relax_passwd_permissions: false
workdir: /myworkdir
user: bob
tags:
- ee_custom:latest
Function of version
Used to identify the configuration format version used in the <span>execution-environment.yml</span><span> file, ensuring that the </span><code><span>ansible-builder</span> tool correctly parses this file.
| Field Name | Type | Default Value | Description |
<span>version</span> |
int | <span>1</span> |
Schema version number; when using <span>ansible-builder</span> 3.x, must be set to <span>3</span> |
Execution Environment Build Process
- 1. Prepare the relevant execution environment definition file and dependency files, and start the build using
<span>ansible-builder</span>or<span>ansible-navigator builder</span>, for example, execute<span>ansible-builder build -vvv</span>in the build directory - 2.
<span>ansible-builder</span>generates the<span>context</span>directory in the working directory for building the image based on the existing configuration files, which contains the<span>Containerfile</span>(or<span>Dockerfile</span>), dependency files, and some scripts for building the image[root@ansible-controller build]# tree context/ 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 3 directories, 12 files - 3. The entire image build is divided into three stages:
- • First stage: Build a BASE image, which will copy the scripts and
<span>entrypoint</span>into the base image and install Python and pip - • Second stage: Based on the BASE image, install Ansible Roles and Ansible Collections
- • Third stage: Based on the BASE image, generate a list of Python packages and system packages to be installed
- • Fourth stage: Based on the BASE image, copy the previously installed Ansible Roles and Ansible Collections, install system packages and Python packages (including default installations and manually set ones), create necessary directories, set permissions for necessary files and directories, set container tags, startup user, and startup command.
<span>--tag</span>) or settings in the configuration file (<span>tags:</span>)This is the default build process; in addition to the default process, custom build instructions can be added through
<span>additional_build_steps</span><span>.</span>
Building an Execution Environment Image
[root@ansible-controller build]# tree .
.
├── ansible.cfg
├── bindep.txt
├── execution-environment.yml
├── requirements.txt
└── requirements.yml
0 directories, 5 files
[root@ansible-controller build]# cat execution-environment.yml
version: 3
build_arg_defaults:
ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: "--pre"
images:
base_image:
name: registry.access.redhat.com/ubi8/ubi-minimal:8.10-1255
dependencies:
python_interpreter:
package_system: python3.12
python_path: /usr/bin/python3.12
ansible_core:
package_pip: ansible-core==2.16.14
ansible_runner:
package_pip: ansible-runner
python: requirements.txt
system: bindep.txt
galaxy: requirements.yml
additional_build_files:
- src: ./ansible.cfg
dest: configs
additional_build_steps:
append_final:
- COPY _build/configs/ansible.cfg /etc/ansible/ansible.cfg
- RUN echo"ADD ansible.cfg to /etc/ansible/!"
options:
container_init:
cmd: '[