Despite having only 5 years at one job under my belt in the IT space, I can make an educated guess that nearly every admin or engineer has had to deal with maintaining systems well beyond their nominal lifetimes. The business demands what it will demand, and sometimes that creates headaches when trying to integrate those legacy machines into your more modern infrastructure management practices.
In my case, we use Ansible to deploy our standard system config to our on-prem estate, and have been experimenting with AWX (the open-source version of Red Hat’s Automation Platform) to schedule some of those deployments to ensure we don’t experience config drift. Unfortunately, with the advent of Ansible 2.4, python2.4 support on managed nodes was deprecated. This is the version of python that shipped with RHEL 5, which meant it became a lot harder to manage those systems while keeping up with the latest features that Ansible had to offer for our newer systems.
In comes the Ansible Execution Environment and ansible-builder. When I first discovered these while playing with AWX, I thought it was the perfect solution to the problem; it’s a containerized environment where you run Ansible playbooks, so just put Ansible 2.3 in the container!
Well it’s not quite that simple. When I began researching how to create my own execution environments with ansible-builder, I eventually discovered a number of assumptions that made creating images with old versions of Ansible a bit tricky.
Some background
An execution environment is basically a container image that has a specific version of ansible_core and ansible_runner in it, along with any extra tools, packages, and collections required for your needs. Most people can get by with the AWX execution environment included in the default install, but if you make heavy use of ansible galaxy, you are probably creating your own EEs as part of your process.
It is possible to build execution environments to manage legacy infrastructure such as RHEL 5 and others, but the tools Ansible provides largely assume you don’t run anything older than RHEL 7 at this point, 8 in some cases. For example, ansible-builder by default wants python 3.9+ and dnf as your package manager.
This can all be worked around. At first I thought this required modifying the source code of ansible-builder itself, but you can actually get images built containing Ansible 2.3.3 while using the latest, unmodified version of builder. We just need to use some of the lesser known options provided in the execution-environment specification.
The execution-environment.yml file
I will give you the definition I use for our RHEL 5 managed nodes first, then provide a bit of an explanation for some of the weirder parts:
---
version: 3
dependencies:
ansible_core:
package_pip: ansible==2.3.3.0
ansible_runner:
package_pip: ansible-runner==2.1.3
python_interpreter:
package_system: python3
python_path: /usr/bin/python3
images:
base_image:
name: quay.io/centos/centos:7
options:
package_manager_path: /bin/yum
additional_build_steps:
prepend_base:
- RUN $PKGMGR install -y gcc python3-devel openssh-clients sshpass
- RUN $PYPKG -m pip install pip==21.3.1 cryptography==3.3.2
- ansible_core definition is self-explanatory, as that is the version of Ansible we want in the image.
- ansible_runner is set to 2.1.3 as that is an older version that requires a slightly less new python3. That is necessary because of the base_image we’re using, centos7 from quay.io.
- base_image is one of the important parts of the definition, since RHEL 5 wants to talk in python2.4 and CentOS 7 has python2 by default.
- package_manager_path is set to yum since ansible-builder will use dnf by default when building the image and that doesn’t exist in CentOS 7.
- We add one additional build step to install system packages that aren’t in the centos7 base_image (ssh anybody?)
- We add another build step to install an older version of the cryptography python package required by Ansible. Newer versions of cryptography are incompatible with Ansible 2.3. Attempts to build/run playbooks result in errors.
Using these settings, you should be able to run the standard ansible-builder build command and generate an Ansible execution environment that contains version 2.3, suitable for running AWX job templates against RHEL 5 and 6 machines.
It may be possible to further optimize this image by using something smaller than a full-blown centos7 base image, but this is the leanest configuration I could manage by simply starting from the base with ansible 2.3.3, then fixing the errors in the build process by installing the necessary packages. Feel free to iterate!