What is Ansible Runner? A lot of us are familiar with Ansible Navigator and Execution Environments (EE’s). They are an integral part of recent versions of Ansible Automation Platform / AWX, and have some nice advantages over running our playbooks with ansible-playbook
. See the previous blogposts about these topics: Navigating Ansible, Execution Environments.
Using EE’s with Ansible Navigator works just fine, as shown in the earlier posts. Under the hood, Ansible Navigator uses Ansible Runner to run playbooks. So let’s have a closer look at how Ansible Runner works!

What is Ansible Runner?
From the Documentation we learn:
“Ansible Runner represents the modularization of the part of Ansible Tower/AWX that is responsible for running ansible and ansible-playbook tasks and gathers the output from it. It does this by presenting a common interface that doesn’t change, even as Ansible itself grows and evolves.”
Sounds good. But what actually IS Ansible Runner? It’s three things:
- A standalone command line tool.
- A reference container image that can be used as a base for our own images (EE’s).
- A python library.
That’s quite a lot! Let’s try to run a simple playbook forrest.yml
in all three ways. For now, we’ll focus on the command line interface, and dedicate a second blogpost on Ansible Runner to the rest of the topics.
The content of our playbook forrest.yml
is as follows:
- name: Run Ansible Run hosts: node1 become: true tasks: - name: Output message ansible.builtin.debug: msg: "{{ debug_msg }}"
But before we start: Why should we use Ansible Runner?
Why Ansible Runner?
Ansible Runner was built for using Ansible as part of automation and tooling that needs to invoke Ansible and consume its results. It accepts most of the cli parameters that the ansible
command knows about. Additionally, Ansible Runner can rely on an input interface that is mapped to a directory structure. So let’s find out how this works!
1. Ansible Runner the CLI
One way to use Ansible Runner is to invoke the ansible-runner
command in our beloved terminal. It’s similar to using ansible-playbook
or ansible-navigator
. However, we don’t want to provide cli parameters directly, but use a folder structure and files to supply information for the Ansible run. The documentation shows an example for the folder structure that we have to set up. Our goal is to provide an extra variable debug_msg
to set the content of the message, provide the inventory file hosts
, and put the playbook forrest.yml
in the correct location. This results in the following structure:
. ├── env │ └── extravars ├── inventory │ └── hosts └── project └── forrest.yml
The content of the file extravars
reads as:
--- debug_msg: "Run, Ansible, Run!"
Our inventory file hosts
is a very simple:
node1 ansible_host=x.x.x.x
Now we are ready to run the playbook forrest.yml
with the ansible-runner
cli. As an additional argument, we have to provide the private_data_dir
, the location of directory containing the structure with the specific information for our Ansible run (aka the metadata directory). In our case, private_data_dir
is /home/ansible/techlab
. This results in the following command:
$ ansible-runner run /home/ansible/techlab -p forrest.yml PLAY [Run Ansible Run] ********************************************************* TASK [Gathering Facts] ********************************************************* ok: [node1] TASK [Output message] ********************************************************** ok: [node1] => { "msg": "Run, Ansible, Run!" } PLAY RECAP ********************************************************************* node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
There’s even more to the env
folder: We can supply environment variables in a file envvars
, provide passwords and an SSH key. An example follows in the next section.
Ansible Runner the CLI with Execution Environments
Now let’s try to run forrest.yml
with the ansible-runner
cli by using an execution environment. Here, things get tricky. The documentation about using Runner with Execution Environments lacks on detail, so let’s investigate on our own!
It seems that ansible-runner
is using no EE even when invoked with the --container-image
option. Trial and error reveals that we need to set both --container-image
and --process-isolation-executable
. Again, we try to avoid explicit command line parameters, and persist these settings in a file settings
, instead. We want to use process isolation as well, which leads to the following set of required files and directories:
. ├── env │ ├── extravars │ ├── settings │ └── ssh_key ├── inventory │ └── hosts └── project └── forrest.yml
and in particular to this content for the settings
file:
--- container_image: default-ee process_isolation_executable: podman process_isolation: true
What about the SSH private key the user ansible
should use inside the container to connect to the server node1
? Helpful ansible-runner would bind mount the local SSH agent’s UNIX-domain socket (SSH_AUTH_SOCK
) into the container runtime. If we don’t want to rely on a running agent, we can pass the SSH key into the container by setting it in the ssh_key
file.
$ cat env/ssh_key -----BEGIN OPENSSH PRIVATE KEY----- b3Blb... ... # your content here... IBAg== -----END OPENSSH PRIVATE KEY-----
But where to specify the remote_user
Ansible should use? Using an ansible.cfg
as is customary with e.g. ansible-navigator
didn’t work, no matter where the file was placed. It’s not clear whether this is an intended use case. An entry for remote_user
in the settings
file was ignored as well. In the end, setting the remote_user
right inside the play turns out to be a working solution. The playbook forrest.yml
now looks like this:
--- - name: Run Ansible Run hosts: node1 remote_user: ansible #<-- THIS LINE IS NEW! become: true tasks: - name: Output message ansible.builtin.debug: msg: "{{ debug_msg }}"
Finally, we are able to run the forrest.yml
playbook with ansible-runner
, using an execution environment:
$ ansible-runner run /home/ansible/techlab/ -p forrest.yml Identity added: /runner/artifacts/8932f312-79da-44cc-a992-d75eaee5a3b5/ssh_key_data (Created for convenience ahead of techlab) PLAY [Run Ansible Run] ********************************************************* TASK [Gathering Facts] ********************************************************* ok: [node1] TASK [Output message] ********************************************************** ok: [node1] => { "msg": "Run, Ansible, Run!" } PLAY RECAP ********************************************************************* node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 $
Note the line starting with “Identity added”. It says that the SSH private key provided in the file ssh_key
is used in the Ansible run. The string “(Created for convenience ahead of techlab)” is the comment of the SSH key. It’s also visible in the public key file (but not in the private key file since there it’s encoded).
In the second part of this mini series, we will have a look at how we can run our playbook with the Ansible Runner container image and with the Python library. Stay tuned!