I wrote earlier about systemd-nspawn, and how it can take much of the fiddly work out of setting up functional chroot environments. I'm a regular Ansible user, and I wanted to be able to apply some of those techniques to my playbooks.

Ansible already has a chroot module, of course, but for some situations -- such as targeting an emulated chroot environment -- that just means a lot of extra work. Using systemd-nspawn makes this trivial.

I've submitted pull request #14334 to the Ansible project, which introduces a new connection driver named nspawn. It acts very much like the chroot driver, but it adds a few new configuration options:

  • ansible_nspawn_args -- analagous to ansible_ssh_args, setting this will override the arguments that are passed to systemd-nspawn by default.

  • ansible_nspawn_extra_args -- analgous to ansible_ssh_extra_args, setting this will append the values to the default systemd-nspawn command line.

Advantages over chroot

Let's say we had a Fedora filesystem mounted on /fedora and we want to run the following playbook:

- hosts: /fedora
  tasks:
    - raw: dnf -y install python libselinux-python python2-dnf
    - dnf:
        name: git
        state: installed

Using the chroot driver, we get:

$ sudo ansible-playbook -i /fedora, -c chroot playbook.yml

PLAY ***************************************************************************

TASK [raw] *********************************************************************
fatal: [/fedora]: FAILED! => {"changed": false, "failed": true, "rc": -6, "stderr": "Fatal Python error: Failed to open /dev/urandom\n", "stdout": "", "stdout_lines": []}

Adding the necessary tasks to our playbook to set up the chroot environment properly will add a lot of additional complexity and will make the playbook substantially less generic. Now compare that to the result of running the same playbook using the nspawn driver:

$ sudo ansible-playbook -i /fedora, -c nspawn playbook.yml

PLAY ***************************************************************************

TASK [raw] *********************************************************************
ok: [/fedora]

TASK [dnf] *********************************************************************
changed: [/fedora]

PLAY RECAP *********************************************************************
/fedora                       : ok=2    changed=1    unreachable=0    failed=0

Ansible in emulation

By taking advantage of ansible_nspawn_extra_args you can create more complex containers. For example, in my last post on systemd-nspawn I showed how to start a container for a different architecture through the use of QEMU user-mode emulation. We can apply the same idea to Ansible with an inventory entry like this:

target
  ansible_host=/fedora
  ansible_connection=nspawn
  ansible_nspawn_extra_args="--bind /usr/bin/qemu-arm"

The above will allow you to run a playbook against a filesystem containing ARM architecture binaries, even though you're running on an x86_64 host.


Systemd-nspawn for fun and...well, mostly for fun

Sun 07 February 2016 by Lars Kellogg-Stedman Tags systemd containers qemu raspberrypi

systemd-nspawn has been called "chroot on steroids", but if you think of it as Docker with a slightly different target you wouldn't be far wrong, either. It can be used to spawn containers on your host, and has a variety of options for configuring the containerized environment through the use ...

read more

Docker vs. PrivateTmp

Sun 18 January 2015 by Lars Kellogg-Stedman Tags docker systemd namespaces

While working with Docker the other day, I ran into an undesirable interaction between Docker and systemd services that utilize the PrivateTmp directive.

The PrivateTmp directive, if true, "sets up a new file system namespace for the executed processes and mounts private /tmp and /var/tmp directories inside it that ...

read more

Starting systemd services without blocking

Tue 02 December 2014 by Lars Kellogg-Stedman Tags systemd

Recently, I've been playing around with Fedora Atomic and Kubernetes. I ran into a frustrating problem in which I would attempt to start a service from within a script launched by cloud-init, only to have have systemctl block indefinitely because the service I was attempting to start was dependent on ...

read more

Private /tmp directories in Fedora

Mon 05 November 2012 by Lars Kellogg-Stedman Tags fedora systemd

I ran into an odd problem the other day: I was testing out some configuration changes for a web application by dropping files into /tmp and pointing the application configuration at the appropriate directory. Everything worked out great when testing it by hand...but when starting up the httpd service ...

read more