Run, Ansible, Run! (Part 1/2)

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:

  1. A standalone command line tool.
  2. A reference container image that can be used as a base for our own images (EE’s).
  3. 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!

 

Kommentare sind geschlossen.