8 minute read

Ansible Navigator is a command-line tool and a text-based user interface (TUI) for creating, reviewing, running and troubleshooting Ansible content, including inventories, playbooks, collections, documentation and container images (execution environments).”

Currently Ansible Navigator for MacOS requires Docker Desktop and doesn’t support Podman due to other technical contraints on how podman handles mounting native folders on MacOS. At the time of writing this blog there is an open issue in the ansible-navigator repo for podman support issue 1259. Like me, if you’re unable to use Docker Desktop you may be looking for an alternative way to run Docker containers on MacOS, and with a general search you’ll find approaches such as using Lima or Vagrant. Lima, which stands for Linux on Mac, is a lightweight solution for running Linux VMs on MacOS, specifically with containerized applications, although it can also be used for non-container applications too.

Installing Lima

I used this blog post by Carlos Nunez as a guide for installing Lima on my laptop.

I’ll include a summary of the commands that I ran, but I’d recommend following Carlos’s blog for a detailed tutorial

╰─ brew install lima docker


╰─ limactl --version
  limactl version 0.19.0

╰─ mkdir ~/lima_machines

╰─ curl -sSLo ~/lima_machines/docker.yaml \
  https://raw.githubusercontent.com/carlosonunez/bash-dotfiles/main/lima_machine.yaml

Edit the dockerfile as stated by the instructions in the file. Specifically:

  # NOTE: Replace %TEMPDIR% with your actual temporary directory as provided by
  # the $TMPDIR environment variable.
  - location: "%TEMPDIR%"
    writable: true

to which mine resolved to

╰─ echo $TMPDIR
  /var/folders/9p/5rymmxbs59d1svryg_7knth80000gn/T/

We’re going to come back to the section in the file later as, we’ll need to update the mounts to include a new directory when we start using Ansible Navigator.

Next start the Docker VM:

╰─ limactl start ~/lima_machines/docker.yaml --tty=false

Perform a final export as mentioned in Carlos’s blog and then we’re good to go.

╰─ export DOCKER_HOST="unix://$HOME/.lima/docker.sock"

╰─ docker ps
  CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Note, we’ll need to add this export to ~/.zprofile, which was not mentioned Carlos’s blog.

At this point we are now successfully running Docker on MacOS without Docker Desktop.

Installing Ansible Navigator

Next, we’re going to now install ansible-navigator and you can find the documented instructions here.

I’ll include a screenshot here just for posterity to have a record of the current instructions at the time of writing this blog.

Ensure that you export the appropriate ansible-navigator installation path as reported in the output of the installation.

╰─ echo 'export PATH=/Users/bpanyar/Library/Python/3.12/bin:$PATH' >> ~/.zprofile

╰─ source ~/.zprofile

After that you should be able to launch ansible-navigator:

╰─ ansible-navigator 

  ---------------------------------------------------------------------
  Execution environment image and pull policy overview
  ---------------------------------------------------------------------
  Execution environment image name:     ghcr.io/ansible/creator-ee:v0.20.0
  Execution environment image tag:      v0.20.0
  Execution environment pull arguments: None
  Execution environment pull policy:    tag
  Execution environment pull needed:    True
  ---------------------------------------------------------------------
  Updating the execution environment
  ---------------------------------------------------------------------
  Running the command: docker pull ghcr.io/ansible/creator-ee:v0.20.0
  v0.20.0: Pulling from ansible/creator-ee
  1e08c7e6aff8: Pull complete 
  ad97261d044b: Pull complete 
  7b05cec1a1b5: Pull complete 
  eaac7334e7ab: Pull complete 
  df17b198186c: Pull complete 
  6a4437d12ad5: Pull complete 
  90e5f6bd07c8: Pull complete 
  65aa82c7a1f1: Pull complete 
  897151f83099: Pull complete 
  19f93933b64e: Pull complete 
  8038a525cde8: Pull complete 
  11c3d85c8b64: Pull complete 
  d29defd3b078: Pull complete 
  Digest: sha256:b496e72a7b581fc8f437fab84d2e7f59c8a4e4ae8191d4c2478dd151c871cf1c
  Status: Downloaded newer image for ghcr.io/ansible/creator-ee:v0.20.0
  ghcr.io/ansible/creator-ee:v0.20.0
 0│Welcome
 1│————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
 2│
 3│Some things you can try from here:
 4│- :collections                                    Explore available collections
 5│- :config                                         Explore the current ansible configuration
 6│- :doc <plugin>                                   Review documentation for a module or plugin
 7│- :help                                           Show the main help page
 8│- :images                                         Explore execution environment images
 9│- :inventory -i <inventory>                       Explore an inventory
10│- :log                                            Review the application log
11│- :lint <file or directory>                       Lint Ansible/YAML files (experimental)
12│- :open                                           Open current page in the editor
13│- :replay                                         Explore a previous run using a playbook artifact
14│- :run <playbook> -i <inventory>                  Run a playbook in interactive mode
15│- :settings                                       Review the current ansible-navigator settings
16│- :quit                                           Quit the application
17│
18│happy automating,
19│
20│-winston

Inspecting Execution Environment Image details

Going into the :images option you can see there is a default image called creator-ee which we’ll use to test running an initial playbook.

  Image                       Tag                 Execution environment                                   Created                           Size
0│creator-ee                  v0.20.0             True                                                    2 months ago                      843MB
1│qus                         latest              False                                                   7 months ago                      306MB

Inspecting the creator-ee image with option 0 lists a number of options of details that you can inspect about the image. By selecting option 1 you should see the following error:

  Warning
  ─────────────────────────────────────────────────────────────────────
  humph. Something went really wrong while introspecting the image.
  Details have been added to the log file
  [HINT] Please log an issue about this one, it shouldn't have happened
  ─────────────────────────────────────────────────────────────────────
                                                                    Ok 

There will be a ansible-navigator.log file generated in your working directory which should show something along the lines of:

2023-10-27T21:08:07.304631+00:00 ERROR 'ansible_navigator.actions.images._parse' Unable to extract introspection from stdout
2023-10-27T21:08:07.305286+00:00 ERROR 'ansible_navigator.actions.images._parse' Image introspection failed (parsed), the return value was: /usr/bin/python3: can't open file '/Users/bpanyar/.cache/ansible-navigator/image_introspect.py': [Errno 2] No such file or directory

Which tells us that the reported ~/.cache directory is not accessible to the EE container. This is where we are going to go back to the docker.yaml file from earlier and update the mount section to incude this directory. We can either update the file we used previously at ~/lima_machines/docker.yaml or update ~/.lima/lima.yaml directly. If you choose to update the previous docker.yaml file, you need to copy it to ~/.lima/lima.yaml.

My mounts: section looks like this with the ~/.cache directory added to the bottom:

mounts:
  - location: "~/src"
    writable: true
  - location: "~/tmp"
    writable: true
  # NOTE: Replace %TEMPDIR% with your actual temporary directory as provided by
  # the $TMPDIR environment variable.
  - location: "/var/folders/9p/5rymmxbs59d1svryg_7knth80000gn/T/"
    writable: true
  - location: "/tmp/lima"
    writable: true
  - location: "~/.config"
    writable: true
  - location: "~/.lima"
    writable: false
  - location: "~/.kube"
    writable: true
  - location: "~/.ssh"
    writable: false
  - location: "~/.gnupg"
    writable: false
  - location: "~/.cache"
    writable: false

Next, we need to restart the Docker VM with:

limactl stop docker && limactl start docker

After restarting Docker and re-launching ansible-navigator, we can now inspect all the image details of the creator-ee image.

Running a playbook with the sample EE.

For this I created a simple ping playbook which just pings localhost.

inventory.yml

systems:
  hosts:
    localhost:
      ansible_host: localhost
      ansible_connection: local

ping.yml

---
- hosts: all
  gather_facts: false

  tasks:
    - name: run ping
      ansible.builtin.ping:
      register: result

    - debug:
        var: result

To run the playbook with the default EE, I’ll change to the directory where this playbook is located and run the following command:

ansible-navigator run ping.yml -i inventory.yml

Note, by default ansible-navigator is configured to use the creator-ee. When creating your own execution environments you can use the --eei argument to specify the name of the execution environment image to use.

Immediately, you should see that the playbook runs without completing any tasks

  Warning
  ────────────────────────────────────────────────────────────────────────────
  The playbook completed without tasks. Redirecting to ':stdout' for review.
  ────────────────────────────────────────────────────────────────────────────
                                                                         Ok 

And by pressing enter you should see something like:

0│ERROR! the playbook: /Users/bpanyar/Downloads/navigator-test/ping.yml could not be found

Again, this is due to the EE container not being able to access the working directory where our playbook is located, so we’ll need to go back and update the mounts: section in the ~/.lima/lima.yaml file and restart Docker again.

- location: "~/Downloads/navigator-test"
    writable: false

after doing that and re-running ansible-navigator run ping.yml -i inventory.yml you should see it execute successfully and be able to see that it completed 2 tasks and drill down into the play for more details.

  Play name        Ok   Changed       Unreachable          Failed      Skipped       Ignored       In progress          Task count                 Progress
0│all               2         0                 0               0            0             0                 0                   2                 Complete

Option 0

  Result         Host                  Number         Changed          Task               Task action                                   Duration
0│Ok             localhost                  0         False            run ping           ansible.builtin.ping                                0s
1│Ok             localhost                  1         False            debug              debug                                               0s

You can see the results of each task by entering its associated option number.

Play name: all:0
Task name: run ping
Ok: localhost                                                                                                                                               
 0│---
 1│duration: 0.18527
 2│end: '2023-12-01T21:49:57.495027'
 3│event_loop: null
 4│host: localhost
 5│play: all
 6│play_pattern: all
 7│playbook: /Users/bpanyar/Downloads/navigator-test/ping.yml
 8│remote_addr: localhost
 9│res:
10│  _ansible_no_log: null
11│  ansible_facts:
12│    discovered_interpreter_python: /usr/bin/python3
13│  changed: false
14│  invocation:
15│    module_args:
16│      data: pong
17│  ping: pong
18│resolved_action: ansible.builtin.ping
19│start: '2023-12-01T21:49:57.309757'
20│task: run ping
21│task_action: ansible.builtin.ping
22│task_args: ''
23│task_path: /Users/bpanyar/Downloads/navigator-test/ping.yml:6

Also notice that there is a json file generated in the working directory for every run of playbook. This is a playbook artifact that contains details about the ansible-navigator settings along with the play output. This can be inspected manually, or replayed in ansible-navigator using the replay argument. This is especially helpful for sharing your playbook output with other or debugging someone elses play when you can’t recreate it in your own environment.

Note, there seems to be a bug with ansible-navigator and you may need to rename your playbook artifact to be able to replay it. The artifact is created with / in the file name and the replay option interprets them as child directories thus is not able to find the artifact.

╰─ ansible-navigator replay ping-artifact-2023-12-01T21/49/57.821234+00/00.json  
Warning: Issues were found while applying the settings.
   Hint: Command provided: 'replay ping-artifact-2023-12-01T21/49/57.821234+00/00.json'

  Error: The specified playbook artifact could not be found:
         /Users/bpanyar/Downloads/navigator-test/ping-artifact-2023-12-01T21/49/57.821234+00/00.json
   Hint: Try again with 'replay <valid path to playbook artifact>'

   Note: Configuration failed, using default log file location. (/Users/bpanyar/Downloads/navigator-test/ansible-navigator.log) Log
         level set to debug
   Hint: Review the hints and log file to see what went wrong.

Conclusion

In summary, its definitely possible to use ansible-navigator without Docker Desktop, with a small amount of effort and some minor technicalities to be aware of. While its not an officially supported installation path, it seems to do the job for building and executing Ansible Execution Environments for development purposes. In this blog I only covered using the default Execution Environment included with Ansible Navigator, but in a future blog I’ll cover creating your own Execution Environments using ansible-builder.

Tips

  • Directories will need to be explicitely mounted for ansible-navigator and the EEs to accesss, so you may choose to mount a parent directory that holds all of your Ansible playbooks.

Many thanks to Carlos Nunez for the simple to follow instructions for installing Lima with Docker.