This post outlines a method for using Docker for testing on Travis CI. It may be useful to you if you are a web application developer who uses GitHub.
I use this setup in my web-based word puzzle generator, so that every change is spun up and tested with a web browser before it is merged.
I got the idea for writing this from a few lines in the docker-compose documentation, which suggested that Docker is an easy way to perform automated testing over a running application:
$ docker-compose up -d $ ./run_tests $ docker-compose down
This snippet was missing some setup and an example app, but these three lines do all the heavy lifting.
The Docker setup
In order to focus on the Docker setup, I made a server which simply responds to TCP requests on port 5000 with the text “Hello World”.
This file is called server.sh, and sits in a directory called foo_server:
#!/bin/sh while true; do # Send 'Hello World' to anybody who connects on port 5000 echo "Hello World" | nc -l 5000 done
Alongside it, I added a Dockerfile to instruct docker to execute this tiny ‘application’ in a container, after installing the dependencies. This machine is built from the Docker-official Debian image:
FROM debian ADD . /usr/share/test-server WORKDIR /usr/share/test-server RUN apt-get update && apt-get install --assume-yes netcat-openbsd CMD ./server.sh
Lastly, a .dockerignore file is used to avoid loading the Dockerfile to the container:
# Ignore docker files Dockerfile .dockerignore
In the directory above, a simple test script, test.sh is used to see that the server is returning the expected output:
#!/bin/sh set -e expected="Hello World" actual=`nc -v localhost 5000` echo "Expecting: $expected" echo "Server says: $actual" if [ "$expected" != "$actual" ]; then echo "Test failed" exit 1 else echo "Test passed" exit 0 fi
Alongside the test file, a file called docker-compose.yml instructs Docker to create a container out of the foo_server example, and forward port 127.0.0.1:5000 to it.
version: '2' services: foo: build: foo_server ports: - "5000:5000" container_name: foo_1
To try it out for yourself, you need a relatively recent version of Docker and docker-compose. The versions provided in Debian were not new enough to execute the examples, but the Docker project provides repos containing newer builds for Debian & Ubuntu. For my distro, the install was:
curl -sSL "https://get.docker.com/gpg" | sudo -E apt-key add - echo "deb https://apt.dockerproject.org/repo debian-stretch main" | sudo tee -a /etc/apt/sources.list sudo apt-get update sudo apt-get install docker-engine sudo pip install docker-compose
The versions this got me were docker 1.11.2, and docker-compose 1.7.1. Straight after the install, I could deploy & test an example locally:
$ docker-compose up --build -d $ ./test.sh $ docker-compose down
The CI setup
I’ll assume that if you’re reading this, you are familiar with the basics of Travis CI. The large block of code below is the .travis.yml file to set up the test machine, then execute the tests against a container.
--- # Use Ubuntu 'trusty' distribution sudo: required dist: trusty install: # Update docker-engine using Ubuntu 'trusty' apt repo - > curl -sSL "https://get.docker.com/gpg" | sudo -E apt-key add - - > echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee -a /etc/apt/sources.list - sudo apt-get update - > sudo apt-get -o Dpkg::Options::="--force-confdef" \ -o Dpkg::Options::="--force-confold" --assume-yes install docker-engine - docker version # Update docker-compose via pip - sudo pip install docker-compose - docker-compose version before_script: - docker-compose up --build -d script: - ./test.sh after_script: - docker-compose down ...
Note: This uses Travis CI’s trusty distribution, which at the time of writing is the newest stable build platform available on Travis CI. This shipped an outdated version of Docker, which had to be installed over. Because the existing Docker was configured, I had to override a debconf prompt, which is why the apt addon syntax was not used to set up dependencies.
The build result for each commit is displayed in Travis CI:
Under this, the output of the passing test script is shown, showing what has been set up:
Using this setup in practice
Moving this from a demo setup to a real setup would be fairly simple:
- Replace the installation with a real software stack
- Replace the server run with a command to serve the application (such as a Apache HTTP, Tomcat or Node)
- Replace the tests with real tests (such as Cucumber or Selenium).
The example in the pre-amble installs a LAMP stack and tests it with Selenium in its CI build.
If your application is a bit larger, your only extra complexity will come from running multiple containers with docker-compose.
Get the code
All of these scripts in a working CI example are available on GitHub: