Out from recent troubles with the official AWX EE image, I decided to try out to build my own EE image using the ansible-builder and use it in my AWX homelab environment.
First of all, what is an AWX execution environment (EE)? In a nutshell, it’s a self contained environment, that enables you to run Ansible tasks in a stable and reproducible environment. It’s a container image which can be shared among others and should be easily manageable. AWX uses an EE to run projects / templates and spins up a container for those runs. It will live during the runtime and probably be deleted after the run has finished. The Ansible project provides those container images for us. They are regularly updated and build, you can follow the activities on the awx-ee project here.
To learn more about AWX and how to get it running on Kubernetes, check out my blog article here (only german).
Why to build your own image
So why you want to create your own EE image if Ansible provides this to us? For me, there are two reasons.
- The awx-ee repository does provide automatically build container images every day. But the last version tag of this image is from over a year ago (
0.6.0). They only tag the most recent image with the
latesttag. The version
0.6.0is no longer useable for me because of outdated software versions and base images. So I use the
latesttag for my execution environment. Which brings the risk, that there are breaking changes in a nightly build (which already happened several times to me). The lack of a
stableor version tag leaves you out in the rain when such breaking changes happen. It’s a frequently discussed topic to use version tags at least from time to time, I can only hope, that by the time you read these lines, they have done so. The most recent case of this happen was the issue described here.
- In case you want to have some private or uncommon Ansible modules / collections always at hand and not want to install it by runtime, this can come handy. Some modules also need Python libraries to be installed which might not be part of the default image.
How to build your own image
In order to build your own execution environment image, you need to install it using the Python package manager pip. You can do it simply by issuing the following command:
pip install ansible-builder
You also need docker or podman running on your machine as well as Python installed. More information on the ansible-builder can be found here.
By this done, you need to know of four files the ansible-builder will need to get you an execution environment image. You can find the listed example code also in my thedatabaseme/awx-ee repository on Github.
This is the starting point for ansible-builder. You can provide custom commands that should run during the build process for instance. In my case, I added a specific Ansible version (by specifying the
EE_BASE_IMAGE parameter) and I added some custom build commands, but mostly, I took over the official awx-ee
--- version: 1 build_arg_defaults: EE_BASE_IMAGE: 'quay.io/ansible/ansible-runner:stable-2.12-latest' dependencies: galaxy: requirements.yml python: requirements.txt system: bindep.txt additional_build_steps: prepend: | RUN whoami RUN cat /etc/os-release append: - RUN echo This image is brought you kindly by thedatabaseme - RUN ls -la /etc - RUN alternatives --set python /usr/bin/python3 - COPY --from=quay.io/ansible/receptor:devel /usr/bin/receptor /usr/bin/receptor - RUN mkdir -p /var/run/receptor - USER 1000 - RUN git lfs install
requirements.txt holds a list of Python dependencies and the version of it. In my case (cause I wanted to fix the issue mentioned above), I specified
cryptography in a specific version. The other entry comes from the official awx-ee project.
This file represents the Ansible collections you want to build into your image. For the sake of this article, I took over the
requirements.yml from the official repository and added some of my favourite collections I use regularly (e.g. community.docker).
--- collections: - name: awx.awx - name: azure.azcollection - name: amazon.aws - name: theforeman.foreman - name: google.cloud - name: openstack.cloud - name: community.general - name: community.vmware - name: community.docker - name: ovirt.ovirt - name: kubernetes.core - name: ansible.posix - name: ansible.windows - name: redhatinsights.insights
This file holds system requirements which will be installed to the container image (using dnf) by ansible-builder. I took this over completely from the awx-ee project.
python38-devel [platform:rpm compile] subversion [platform:rpm] subversion [platform:dpkg] git-lfs [platform:rpm]
Time to build
Let’s place the above three files in a directory of your choice and fire up ansible-builder with the following command:
❯ ansible-builder build --tag thedatabaseme/awx-ee:0.0.1 --container-runtime docker -f execution-environment.yml Running command: docker build -f context/Dockerfile -t thedatabaseme/awx-ee:0.0.1 context Complete! The build context can be found at: /mnt/e/Projekte/Ansible/awx-ee/context ❯ docker image ls | grep ee thedatabaseme/awx-ee 0.0.1 7b56f9d35080 10 minutes ago 1.85GB
As you can see, I had to specify the
--container-runtime parameter with
docker. The default is podman, so you can leave this parameter out if you’re running podman as your container environment.
You may push the image now to the container registry of your choice. In my case it’s Github again (
Use your own image
Now that the image is pushed, all is ready to use it. So head over to your AWX and select
Execution Environment from the left menu bar. You should see something like in the image below. Press
Add to make our new EE image available.
Insert your detailed information on the execution environment. If your image is on a private repository, you need to specify the credential set in here.
I choose to always pull the image before running the container. In case of using a version tag, this is probably not needed. When using the
latest tag, I would recommend you to choose the “Always pull” option.
Now you have several possibilities to specify which execution environment a template run should use. You can specify it on instance group level, on project level or on template level. Each following overwrites the setting of the previous. For testing, I specified this for a specific template. Checking my Kubernetes cluster, I could see, that the spun up container pulls the correct image and runs the job, using my execution environment.
The last thing you also might want to change, is the so called “Control plane execution environment”. It is used for AWX internal tasks and inventory syncs and it’s not changeable via the WebUI. To change the used image for this, you need to update your AWX Operator CRD in Kubernetes. Here’s is an example:
--- apiVersion: awx.ansible.com/v1beta1 kind: AWX ... spec: image_pull_policy: Always control_plane_ee_image: ghcr.io/thedatabaseme/awx-ee:0.0.1 ...