Creating and using ansible execution engine in Mac – Apple Silicone [M1]

With ansible 2.x, ansible requires an execution environment to run playbooks.
This was to increase the portability of ansible development. However, with Apple’s new M1/M2 silicone, it has made things rather tricky.

Short Answer:

If you decide to use Red Hat’s certified EE minimal images, right at the end, it checks for the validity of the HOST machine.

Since I am using a MAC, it won’t find the valid subscription, therefore it will fail with below error;

#20 3.932 + /usr/bin/microdnf install -y --nodocs --setopt=install_weak_deps=0 --setopt=rhel-8-for-x86_64-appstream-rpms.excludepkgs=ansible-core subversion
#20 4.064 
#20 4.064 (microdnf:61): librhsm-WARNING **: 23:54:03.115: Found 0 entitlement certificates
#20 4.075 
#20 4.075 (microdnf:61): librhsm-WARNING **: 23:54:03.128: Found 0 entitlement certificates
executor failed running [/bin/sh -c /output/install-from-bindep && rm -rf /output/wheels]: exit code: 1

Longer answer:

YES, you can still create an EE using the community images.


  • Brew
  • Ansible
  • Ansible-builder
  • Ansible-navigator
  • docker desktop
  • an environment variable “DOCKER_DEFAULT_PLATFORM=linux/amd64”

Core issues:

  1. Ansible Execution Engine container images are built for x86_64/amd64 whereas MAC M1/M2 are based on arm64
  2. ansible-builder’s default container runtime “podman” is not available in MAC M1


  • Use Docker desktop to emulate x86_64 or AMD64
  • Use an environment variable to set the docker’s default platform to be ’emulated” x86_64/amd64
  • use “–container-runtime docker” option in ansible-builder to switch from the default “podman” to “docker” as the container runtime.

Command to use:

% ansible-builder build --container-runtime docker -v3 -t <EE TAG NAME> <CONTEXT NAME>

Below is the outcome from my command:

Ansible Builder is building your execution environment image. Tags: <EE TAG NANE>
File context/_build/requirements.yml is already up-to-date.
File context/_build/requirements.txt is already up-to-date.
File context/_build/bindep.txt is already up-to-date.
Rewriting Containerfile to capture collection requirements
#21 0.362 lrwxrwxrwx 1 root root     12 Jan 12 09:05 yum.conf -> dnf/dnf.conf
#21 0.362 drwxr-xr-x 1 root root   4096 Apr 28  2022 yum.repos.d
#21 DONE 0.4s

#22 exporting to image
#22 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00
#22 exporting layers
#22 exporting layers 1.3s done
#22 writing image sha256:86e1fe66e05724035fbcf2ecfb3492e70581fd04027ebbe687cad99a00c25d2b done
#22 naming to<EE TAG> done
#22 DONE 1.3sComplete! The build context can be found at: /Users/david.joo/Documents/ansible/playpan/context

% docker images               
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
<EE TAG NAME>              latest    86e1fe66e057   15 minutes ago   1.22GB

DevOps vs ITIL ?

Recently, I came across an article that says that “DevOps is opposite to ITIL”.

To be frank, I never thought DevOps to be the opposite of ITIL. The argument in the article was that ITIL is slow, and DevOps is faster, which meets one of the current IT business goals;

  • Reduce Time to Market
  • Reduce Operational Cost
  • Increase efficiencies

Whereas ITIL has so many steps that it is slowing the “go to market” speed.

To me, DevOps still does require checks & balances and security gatekeepers, and traceability, which is one of the few key thoughts around ITIL. The major difference I believe is “automation”. When ITIL was initially thought through and established, automation was still available in various forms and shapes, but it was seen as very top-level IT skills and looked at as not that easy to implement. For that, process and people became more important and somewhat it brought a bit more complexity and speed.

However, with tools like ansible, terraform, and so on, I believe, a few steps of the ITIL could be speedup through automation.

Again, I still don’t see the argument of DevOps <-> ITIL. As I said, even speed-wise I don’t think the argument exists.

To me, the important part of this day and age is that, with any enterprise, for security reasons, audibility, and traceability, make sure you build proper checks and balances into your DevOps practices, which you should be able to learn a thing or two from the ITIL practices.

Information about Red Hat live kernel patch (kpatch)

Kernel live patching has been around since about 2010 through various forms in Linux distributions.

Even with Oracle’s ksplice and so on, there have been other people who has been using the live patch capabilities.

However, as a RH employee, I always had a more skeptical view on safety of it.

Recently I had a customer asking for more detailed information, and had a chance to do bit of research on this topic.

First Red Hat’s kpatch;

  • It has formally released and supported from RHEL 8.1, RHEL 7.7; RHEL-7.6, and the kernel-3.10.0-957.35.1.el7.
  • RH does not provide kpatch for all kernel patches but available for selected Important and Critical CVEs.
  • Kpatch patches are cumulative. – You can’t pick and choose! – It means that when you get a new live kernel patch for the kernel, it will have all the fixes of the previous live kernel patch, along with the new fixes. You can safely upgrade the loaded live kernel patch to a newer version.
  • Starting with RHEL 8.5 and kernel-3.10.0-1160.45.1.el, kernels will receive live kernel patches for 6 months. Therefore customers will need to upgrade the kernel and reboot at least twice per year.

How does kpatch work?

If you’re running a kernel version that supports it, you can (and should) take advantage of live kernel patching. This code execution method works alongside kernel probes and function tracing. Instead of relying on redirection using a breakpoint for kernel probes or a predefined location (in the case of function tracing), live patching is generally done by redirecting the code as close to the function entry as possible.

This new method allows for a function to be immediately redirected through a ftrace handler, so instead of calling an older, vulnerable function, it is redirected to a patched version of the function.

To reiterate it;
The kpatch kernel patching solution uses the livepatch kernel subsystem to redirect old functions to new ones. When a live kernel patch is applied to a system, the following things happen:

  1. The kernel patch module is copied to the /var/lib/kpatch/ directory and registered for re-application to the kernel by systemd on next boot.
  2. The kpatch module is loaded into the running kernel and the new functions are registered to the ftrace mechanism with a pointer to the location in memory of the new code.
  3. When the kernel accesses the patched function, it is redirected by the ftrace mechanism which bypasses the original functions and redirects the kernel to patched version of the function.

What’s the differences between kpatch and other live kernel patch solution?

For kpatch vs kGraft, there has been detailed discussion at the linuxplumber conference in 2014.

More to read:

Building an execution environment in a disconnected environment

Today is just for me to add a link for me to remember.

Below is a great summary of the issue and how it can be resolved when you try to build an ansible execution environment in a disconnected environment.

Creating an ansible execution environment with a container image from a container repository with a self-signed certificate

When you try to build an ansible execution environment, you may need to use a container repository with a self-signed certificate.

This will fail with the following error;

ERROR! Unknown error when attempting to call Galaxy at 'https://<URL>/api': <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)>
Error: error building at STEP "RUN ANSIBLE_GALAXY_DISABLE_GPG_VERIFY=1 ansible-galaxy collection install $ANSIBLE_GALAXY_CLI_COLLECTION_OPTS -r requirements.yml --collections-path "/usr/share/ansible/collections"": error while running runtime: exit status 1

This can be resolved by adding “ANSIBLE_GALAXY_CLI_COLLECTION_OPTS : “–ignore-certs” “

[svc_aap_install@AGAEALP3001264 ee-infoblox-build]$ cat execution-environment.yml 
version: 1

  EE_BUILDER_IMAGE: '<URL>/ansible-builder-rhel8'
  EE_BASE_IMAGE: '<URL>/ee-supported-rhel8'

Testing newly create execution environment

Based on previous posts, you probably have created an ansible execution environment.

After you have created an execution environment, how do you test it?

The new ansible CLI tool to run an ansible playbook is called “ansible-navigator”.
It’s not only a ansible-playbook execution binary, but it has more features to it such as:

  • Review and explore available collections
  • Review and explore current Ansible configuration
  • Review and explore Ansible documentation
  • Review execution environment images available locally
  • Review and explore an inventory
  • Run and explore a playbook

But for the testing, this is what you need to do to test the newly created execution environment.

$ ansible-navigator run -eei localhost/<newly created EE name> --pp never <test ansible playbook>.yml

From above, the important option is “–pp never” which stands for “pull policy” “never”.
This means that, since it’s already on the localhost, please don’t download the image.
If for some reason, you forget the option, you will see the following error;

Trying to pull localhost/<new ee name>:latest...
WARN[0000] failed, retrying in 1s ... (1/3). Error: initializing source docker://localhost/<new ee name>:latest: pinging container registry localhost: Get "https://localhost/v2/": dial tcp connect: connection refused
WARN[0001] failed, retrying in 1s ... (2/3). Error: initializing source docker://localhost/<new ee name>:latest: pinging container registry localhost: Get "https://localhost/v2/": dial tcp connect: connection refused
WARN[0002] failed, retrying in 1s ... (3/3). Error: initializing source docker://localhost/<new ee name>:latest: pinging container registry localhost: Get "https://localhost/v2/": dial tcp connect: connection refused
Error: initializing source docker://localhost/<new ee name>:latest: pinging container registry localhost: Get "https://localhost/v2/": dial tcp connect: connection refused
[ERROR]: Execution environment pull failed

Also, the ansible-navigator’s default UI mode is “TUI” mode rather than printing out errors to stdout. If you would like to run ansible-navigator in stdout mode, just add an option;

$ ansible-navigator run --eei localhost/<newly created ee> --pp never <test ansible>.yml --mode stdout

Prep’ng a RDS Database instance for Satellite 6 installation

This is a note for myself on what had to be done to prep RDS database to connect it with Red Hat Satellite 6 installation.

Currently, Red Hat Satellite using RDS doesn’t work for 2 reasons;
* For Red Hat Satellite 6.10, Postgresql 12.1 the only version of DB supported as an external DB

While I was trying to install oldest Postgresql available was 12.5.

  • Require “rh-postgresql12-postgresql-evr” pkg
    Installation will fail saying ;
    rh-postgresql12-postgresql-evr pkg with a matching version with the RDS, which doesn’t exist.
postgres=> GRANT foreman to postgres;
postgres=> GRANT candlepin to postgres;
postgres=> GRANT pulp to postgres;
  • Create databases

Ansible Automation Platform – What is Ansible Automation Execution Environment i.e. EE?

With Red Hat’s Ansible Automation Platform 2.x, one of the big change is the introduction of Ansible Execution Environment.

Then questions rise;
* What is an Ansible Execution Environment?
* What is it for?

What is an Ansible Automation Execution Environment?

Below is a simple diagram summarising what it is.

High level overview of Automation Execution Environment

It is an optimised container environment that contains required “binaries”, “python+other Libraries” and ansible collections to execute an Ansible playbook(s).

Business/Technical Problems to solve:
To Provide a simplified & consistent execution environment to enhance automation development experiences

When a developer/user develops automation on their own environment and shares their own ansible playbooks with other team members, depending on their own development environment vs others, the automation experience could be very different. (Developing Ansible playbooks in a Mac vs Linux)

By creating and using the Ansible Automation Execution Environment, it provides the same development/execution experience.

– Multiple python environments to manage that creates maintenance overhead.

One of the main struggles was that Ansible Tower users had requirements for multiple python virtual environments as the number of users or number of use cases increased. E.g. for use cases, requirements of python 2.7 vs python 3.x or some modules requiring specific versions of python modules.

Above has resulted, within Ansible tower creating multiple python virtual environments, and if you have a cluster of ansible tower nodes, the administrator had to ensure all tower nodes have exactly the same python virtual environment configurations.

Ansible Automation Platform Execution Environment & tzdata

With a colleague of mine, we were testing migration of a ServiceNow – system provisioning ansible workflow from Ansible 2.9 -> Ansible Automation platform 2.x and hit an issue.

No such file or directory: '/usr/share/zoneinfo/

My immediate thought would be that “tzdata” pkg is not installed on the UBI.

So added “tzdata” into bindep.txt and rebuild the EE image, but it didn’t work with error saying that nothing to install. (i.e. its already installed, just the file is not available, tested this with “append” in execution-environment.yml

[3/3] STEP 6/6: RUN ls -la /usr/share/zoneinfo/
ls: cannot access '/usr/share/zoneinfo/': No such file or directory
Error: error building at STEP "RUN ls -la /usr/share/zoneinfo/": error while running runtime: exit status 2

To get rid of this issue, I had to just use append to “reinstall” using microdnf tzdata as below;

$ cat execution-environment.yml
version: 1
  galaxy: requirements.yml
  system: bindep.txt

    - RUN microdnf reinstall -y tzdata
    - RUN ls -la /usr/share/zoneinfo/
[3/3] STEP 6/7: RUN microdnf reinstall -y tzdata
Downloading metadata...
Downloading metadata...
Downloading metadata...
Downloading metadata...
Downloading metadata...
Package                                Repository       Size
 tzdata-2021e-1.el8.noarch             ubi-8-baseos 485.0 kB
   replacing tzdata-2021e-1.el8.noarch
Transaction Summary:
 Installing:        0 packages
 Reinstalling:      1 packages
 Upgrading:         0 packages
 Obsoleting:        0 packages
 Removing:          0 packages
 Downgrading:       0 packages
Downloading packages...
Running transaction test...
Reinstalling: tzdata;2021e-1.el8;noarch;ubi-8-baseos
--> 0a9e9e0a1ed
[3/3] STEP 7/7: RUN ls -la /usr/share/zoneinfo/
-rw-r--r--. 1 root root 19419 Sep 20 16:34 /usr/share/zoneinfo/
[3/3] COMMIT servicenow-ee-29

Ansible Automation Platform – developer high-level workflow

For a customer recently, I had to talk about with Ansible Automation 2.x, what is required to develop ansible playbooks.

Here is a high-level workflow diagram that I drew;

Ansible Automation Platform – developer high-level workflow

So what it is that… When you are writing a playbook and testing it, you need the following components:

  • Ansible IDE tool – my current favourite is VSCode, because there are so many nice extensions + Red Hat recently have released ansible extension
VSCode Ansible extension
  • Ansible-Core – the command line tool, the language and framework that makes up the foundational content before you bring in your customized content.
  • Ansible-Builder – to build execution environments
  • Ansible-navigator – to run, test playbooks with execution environments

If you haven’t built an execution environment, the very first thing that you need to do is to build an execution environment, as below:

4 files that you need to create are;

  • bindep.txt – Bindep is a tool for checking the presence of binary packages needed to use an application / library, so whatever is defined in this file will be installed.
  • requirement.txt – The python entry points to a Python requirements file for pip install -r …
  • requirement.yml – Outlines ansible collection requirements for galaxy to download and include into the execution environment.
  • execution-environment.yml – A definition file as an input and then outputs the build context necessary for creating an Execution Environment image

Detailed examples can be found in:

Once the required execution environment is ready, it can be shared across your colleagues to enhance the collaboration experiences through consistencies.

Also, now you can start to develop an ansible playbook;

Finally, once you are happy with the playbook and the execution environment, it should be uploaded and managed in source management systems:

  • playbooks – Source Control Management Systems – e.g. github, gitlab….
  • EE image – e.g.) Automation hub,, artifactory…

Then those can be properly leveraged by Ansible Automation Platform.