Creating an execution environment image
This post will cover the process of using bash, podman, and ansible builder.
We’ll tackle this using various files as the container definition. Then a small bash script to run the build, create the container, and upload it to Private Automation Hub. This post is a bit long, check the links if you need to jump around.
Creating an execution environment file
Creating the build context and building
Prerequisites
If the needed software is not installed, this section will briefly cover installing the required components. This only covers installing on the dnf package manager on RHEL like systems.
sudo dnf install podman
# Install Ansible builder to create the EE image
pip install ansible-builder
# Ensure you can login to the Private Automation hub if required
podman login https://url.website.org username password
Creating requirements files
For Ansible and Python dependencies there are some files that must be created. In this post we will cover the files requirements.yml, requirements.txt, and execution-environment.yml. I plan to cover more complex cases in a future post.
I find it easiest to start with Ansible dependencies. This way you can use the module documentation to build the requirements txt file for pip installs.
Let’s create a simple example of a requirements.yml file that installs from Ansible Galaxy as well as private automation hub.
---
collections:
- name: community.general
- name: awx.awx
- name: custom.role_collection
source: https://private-automation-hub.com/api/galaxy/content/published
To build the requirements.txt file it is useful to view the collection documentation to see what Python libraries are required. I’ll show a small example below but some research may be required, especially for large collections such as community.general. Example truncated for readability.
ansible
ansible-runner
bcrypt
cachecontrol
cachetools
certifi
chardet
cryptography
decorator
iso8601
isodate
Jinja2
jmespath
Creating a package list file
Another file that is typically needed is the file to install any OS package dependencies from dnf, apt-get, etc.
Create a file and assign any name to it. I’ll call this one dnf.txt. See the example below.
bind-utils [platform:rpm]
crypto-policies [platform:rpm]
dos2unix [platform:rpm]
findutils [platform:rpm]
gcc [platform:rpm]
hostname [platform:rpm]
iputils [platform:rpm]
krb5-devel [platform:rpm]
krb5-libs [platform:rpm]
krb5-workstation [platform:rpm]
nfs-utils [platform:rpm]
openssl [platform:rpm]
openssl-devel [platform:rpm]
openssl-libs [platform:rpm]
poppler-utils [platform:rpm]
python3-devel [platform:rpm]
python3-gpg [platform:rpm]
python3-pycurl [platform:rpm]
python3-pyOpenSSL [platform:rpm]
samba-client [platform:rpm]
texlive [platform:rpm]
tzdata [platform-rpm]
unzip [platform:rpm]
wget [platform:rpm]
which [platform:rpm]
Creating an execution environment file
The last file to create is the actual execution envrironment yaml. This is the main thing Ansible builder reads to build out the ContainerFile and other necessary files. There is an example available in the documentation. I’ll also show my own example below.
---
version: 3
build_arg_defaults:
ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: "-c"
images:
base_image:
name: 'registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest'
options:
package_manager_path: /usr/bin/microdnf
user: '0' # root
dependencies:
python_interpreter:
package_system: python3.9 # (optional) name of a Python interpreter OS package to install
python_path: /usr/bin/python3.9 # (optional) path to the Python interpreter to use
galaxy: requirements.yml # change this field if your file has a different name
python: requirements.txt # change this field if your file has a different name
system: dnf.txt # change this field if your file has a different name
additional_build_files:
- src: ansible.cfg # Not covered in this post but if you need private automation hub, you'll need to create and edit this file
dest: configs
additional_build_steps:
prepend_galaxy:
- ADD _build/configs/ansible.cfg ~/.ansible.cfg
- RUN ansible-galaxy collection install servicenow.itsm --upgrade --collections-path /usr/share/ansible/collections/ansible_collections
prepend_final: |
RUN whoami
RUN cat /etc/os-release
append_final:
# Install AWS CLI as an example of including other tasks at the end of the build.
- RUN mkdir ~/.aws
- RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
- RUN unzip awscliv2.zip
- RUN ./aws/install
- RUN aws --version
- RUN rm -rf awscliv2.zip
- RUN rm -rf aws
Creating the build context and building
For this section I typically have a bash script that I’ll adjust as needed so I don’t forget any steps.
# Set variables at top for re-use
private_hub="ansible-hub.company.com" # Replace with your private automation hub
EE='ee_company_aws'
# Move to the build directory if necessary
cd ~/github/ee-creation
# Build the context directory
ansible-builder create -v 3 # Make sure this matches the version in the execution-environment.yml file
# Optionally copy and additional files to the context directory. Evaluate this for your own build.
cp -r -v files/* context
# Pull the latest execution environment from Red Hat, skip if this is already stored locally
# NOTE: This requires a support relationship with red hat. There are free alternatives available.
EE_supported='registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel9:latest'
PA='password'
podman login -u 'red_hat_login' -p $PA registry.redhat.io
podman search registry.redhat.io/ee --format json |jq '.[]|.Name'
podman pull $EE_supported
# Build the execution environment, https://ansible.readthedocs.io/projects/builder/en/latest/usage/#the-build-command
ansible-builder build --tag=$privatehub/$EE # Some optional parameters below
# --squash new --verbosity 3 # squashing is optional, only use if image size is a concern
# Login to the private hub and push image. Optionally stop here to perform tests of your playbook.
podman login -u=user.name -p='password' $private_hub
# Push the image to the private hub
podman push $private_hub/$EE:latest
Once you follow through this script step by step (or try running it all at once!), you should see the upload of the container underway.
If you encountered any errors during the build, take a look at the error and check your generated ContainerFile and other files to see what is causing the problem. Generally the build is very verbose and the problem line is easily identified.
There are some additional steps to ensuring this image is available in your Ansible Automation Platform. This post is already long so I am going to save that for another post.
Thanks for reading. Feel free to reach out to me with questions or feedback.