Saturday, 4 April 2015

How to test ansible roles with docker

Ansible roles can be difficult to write tests for.  They change the state of a machine and may not be able to run on the distribution of linux that your development or CI machine runs.   Docker solves both of these problems very nicely. Here I will discuss how with an example project on github.

Background

Before adopting this strategy I found myself testing ansible roles on the actual machine they were being deployed to.  This is bad because:

  • It's error prone (previous failed attempts can leave the machine your testing on in a state that is invalid).
  • You have to write more code to rollback what ansible has done so you can test again.
  • Not being able to run locally increases you edit, compile, debug cycle.
  • In order to automate this for CI you need to set aside a machine/VM.

How to test an ansible role

Jeff Geerling has a great blog post on testing ansible roles with travis ci which was adapted from his book Ansible for DevOps.  His post shows you how to test that:

  • role syntax is ok.
  • role can be applied to localhost.
  • role is idempotent (i.e. can be applied again to localhost resulting in zero changes).

This is a great approach.  However it doesn't quite work for me since:

  • I'm using a different distribution of linux on my dev machine to my production machines that my roles are designed for.   
  • Even if I could run them locally, I don't want to as I'll have to undo the actions in order to run the tests again.
  • I'm not using travic ci.

Testing ansible role with docker

See my sample project on github.  In short, this involves the exact same steps as above but just replacing localhost with a docker container.

Diagram showing flow of bash script calling ansible which applies the role to a docker container


This diagram does not show the complete steps which are as follows:

  • Test role syntax locally.
  • Test role can be applied to docker container via ssh.
  • Re-apply the role to the docker container and check it results in zero changes.
  • Check that the docker container is in the correct state.  

All I really needed was to write the bash script and find a docker image that was "red hat like" that came with ssh.  I found the tutum centos docker image which was perfect.

This testing approach has a number of benefits:
  • Can apply role to a different linux distribution than your localhost.  For example if you use a Debian Linux distribution locally but want to test your role against a CentOs distribution, this is possible by using a docker image that mimics the distribution of your choice.  This can have the affect of simplifying your role as you only have to worry about one platform (e.g. not having to use the ansible apt and yum module with when conditions as per this article)
  • Since the docker container is destroyed on the next run of the test, it can be run multiple times without prior runs affecting future runs.
  • Testing via ssh and not localhost.  Ansible should behave the same way when applying a role to localhost as for ssh, but testing via ssh is more likely a closer test to your real world setup.
  • Test can be extended to run against different docker containers.  Perhaps you have different machines in different states which your role will need to handle, this can be tested by applying your role to different docker containers.
The drawbacks:
  • You need docker installed.
  • Finding a docker image that is in the correct state can be hard, might require you to create one yourself.
  • My bash script is a little complicated and might be hard to maintain!  

 

1 comment:

  1. Nice idea! But does the image have a full blown systemd installation? In my ansible roles I use systemd (service) to control running applications and so on

    ReplyDelete