In this blog I will describe a reusable approach to testing Docker that I have been working on.
By "testing Docker" I mean the performing the following actions:
Static code analysis of the Dockerfile (i.e., is the file syntactically valid and written to our expected standards?)
Unit testing the Docker Image created by performing a build with our Dockerfile (i.e., does our Dockerfile look like it created the Image we were expecting?)
Functional testing the Container created by running an instance of our container i.e. when running does it look and do as we expected?
I wanted a solution that was very easy to adopt and extend so I chose to:
Implement it in Docker so that it will work for anyone using Docker
Use Docker Compose to make it as easy to trigger
Use Ruby because it is fairly widespread as a required skill in infrastructure-as-code people and because the docker-api Gem is very powerful, albeit expects you to learn more about the Docker API in order to use it
Use RSpec and ServerSpec as testing framework because they have good documentation and the support BDD
So what is the solution?
Essentially it is a Docker image called test-docker. To use it, you must mount-in your "Dockerfile" and your "tests" directory, it then:
Runs Dockerlint to perform the static code analysis on the Docker file
Runs your tests which I encourage you write for both inspecting the image and testing a running container
How to see it in action?
To run this you need Docker installed and functioning happily. Personally I’m using:
A Windows laptop
Docker Toolbox which gave me: Docker-machine which manages a Linux virtual machine for me running on a local installation of Virtual Box
Docker-compose installed (I did it manually)
Git bash aka Git For Windows as my terminal
With the above or equivalent, you simply need to do:
You should see an output like this:
All good. But what happened? Well everything I’ve said we wanted to happen, against the test-docker tool.
You can also try out another example e.g.:
So how to use this for your own work?
Hopefully you’ll agree this is very easy (at least to get started):
Replace the Dockerfile in the root of the test-docker folder with your own Dockerfile (plus any other local resources your Dockerfile needs)
Run the following (this time we allow docker-compose to use the default configuration file which you also pulled from Git:
You will find out what Dockerlint thinks of your code, followed by finding out whether by extreme luck any of the tests that were written for the test-docker image (as opposed to your image) pass
Open the rb file (in tests/spec) and update it to test your application using anything that you can do to a stopped container using the docker-api
I suggest remove the .git folder and initialize a git repository to manage your Dockerfile and your tests.
Functional tests that run the container require two subtly different approaches according to whether your Docker image is expected to run as a daemon or just run, do something and stop. In the former case, you can use a lot of Serverspec functionality. In the latter, your choices are more limited to running the container multiple times and in each case grabbing the output and parsing it.
There were a surprising number of things I had to learn on the fly here to get this working, but I don’t want this blog to drag on. Let me know how you get on @markosrendell and I will happily share more, especially when any of magic things don’t work as expected—for example when writing tests.
I’ll leave you with my current list of things I want to improve:
Make work with Ruby slim (the image is huge)
Get working with Inspec instead of ServerSpc
Provide better examples of tests
I should really draw a diagram to help anyone new to this understand all this inception computing…
I took a huge amount of help from: