incomplete.io

docker containers for offline ansible testing

introduction

We're constantly on the go. There's a lot of potential downtime spent on flights and in airports without a lot of consistent connectivity. At times, it's helpful to be able to test improvements and adjustments to our Ansible playbooks whilst 30,000 feet above solid ground.

In this brief article, we'll look at a quick way to bring up a very bare-bones Ubuntu container under Docker as a way to allow us to test an Ansible playbook. Doing this ahead of time, means that we have a working playpen for Ansible on the go... at least for tasks that don't require connectivity.

Dockerfile

We'll define our container as a Dockerfile format file. This allows us to check in the definition of the container rather than having to maintain a binary lob image of the container and move that between laptops. It makes ongoing maintenance of the image easier over time too -- simply change the Dockerfile, destroy the old image and container and recreate it.

A few things about what we want to achieve in this Dockerfile:

  1. Use Ubuntu 16.04 as the base distribution (in this case).
  2. Update the packages to the latest.
  3. Install Ansible dependencies -- OpenSSH and Python.
  4. Configure OpenSSH to allow us to log in as root with our ssh keys.
  5. Start and port-forward the OpenSSH server.

Here's the file contents, which will be saved as a plain text file called Dockerfile:

01: FROM ubuntu:16.04
02: 
03: # Update packages list, packages and install necessary packages. The updates
04: # here are optional, but the installation of openssh-server and python are
05: # required to use this container with ansible.
06: RUN apt-get update && apt-get dist-upgrade -y && apt-get autoremove -y
07: RUN apt-get install -y openssh-server python && apt-get clean
08: 
09: RUN mkdir /var/run/sshd
10: 
11: # By default root account is disabled and not allowed to login using a password
12: # through sshd. We'll add our ssh public key to the authorized_keys file to
13: # allow public/private key logins.
14: RUN mkdir /root/.ssh
15: COPY /home/incomplete.io/.ssh/id_ecdsa.pub /root/.ssh/authorized_keys
16: RUN chmod 700 /root/.ssh
17: RUN chmod 600 /root/.ssh/authorized_keys
18: 
19: EXPOSE 22
20: CMD ["/usr/sbin/sshd", "-D"]
21: 

building and starting the container

First, we'll need to build a container image from the Dockerfile template we've created. This will pull bits from wherever, so this part needs to be done with connectivity to the outside world by default. In this case, we'll call the template ansible_victim and the location of the Dockerfile template is the current (.) directory:

1: sudo docker build -t ansible_victim .
2: 

This should succeed and the output of sudo docker images should contain an image called ansible_victim, or whatever you chose to call it.

Finally, and this can be done offline, we instantiate and start a container from the image. In the example below, we'll use the name ans_vic1 as our container instance name. This will be one of the containers we will point our Ansible inventory to.

1: sudo docker run -d -P --name ans_vic1 ansible_victim
2: 

You should be presented with a large string representing that container instance and if you execute the sudo docker ps command, you should see your container. Make note of the port number under the PORT column. The -P option tells Docker to automatically perform this port mapping and the -d option starts the container in the background -- Ansible will connect to the container by SSH.

using ansible

We'll cover Ansible and its playbooks later, but to demonstrate our container working, we'll create a simple playbook and try it against our container.

Create a file called ansible-hosts that contains the following, replacing the port number with the port number shown in the output of sudo docker ps command above:

1: [ansible_victims]
2:     127.0.0.1:32768
3: 

And then add the following playbook content to a file called ansible_test.yml:

1: ---
2: - hosts: ansible_victims
3:   remote_user: root
4: 
5:   tasks:
6:     - name: Gather container hardware info
7:       setup:
8:           gather_subset: hardware
9: 

And finally run the playbook against the container:

1: ansible-playbook -i ./ansible-hosts ansible_test.yml
2: 

You should see the following output:


PLAY [ansible_victims] *********************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [Gather container hardware info] ******************************************
ok: [127.0.0.1]

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0   

    

finishing up

So you can see how straightforward it is to bring up a Docker container to act as a testbed for Ansible orchestration to allow for development and testing without necessarily having access to live systems. Here are a few quick tips to help extend what we have here:

Twitter: @IncompleteIO