Tutorial: How to test your docker image in half a second

In this tutorial we’ll walk through a really simple way to write and test docker images. The tests we’ll write will validate the official Nginx docker image using Goss in ~0.5s.

When you’re done with this tutorial you’ll have a small YAML file that describes your docker image’s desired state. This will allow you to test this:

docker run -p 8080:80 nginx

With this:

dgoss run -p 8080:80 nginx

The tests will run in about a half second, and output the following:

INFO: Starting docker container
INFO: Container ID: 25d23a24
INFO: Running Tests
File: /var/log/nginx/error.log: exists: matches expectation: [true]
File: /var/log/nginx/error.log: linkedto: matches expectation: ["/dev/stderr"]
File: /var/log/nginx/error.log: filetype: matches expectation: ["symlink"]
File: /var/log/nginx/access.log: exists: matches expectation: [true]
File: /var/log/nginx/access.log: linkedto: matches expectation: ["/dev/stdout"]
File: /var/log/nginx/access.log: filetype: matches expectation: ["symlink"]
Process: nginx: running: matches expectation: [true]
Port: tcp:80: listening: matches expectation: [true]
Port: tcp:80: ip: matches expectation: [["0.0.0.0"]]
HTTP: http://localhost: status: matches expectation: [200]
HTTP: http://localhost: Body: matches expectation: [Welcome to nginx!]
Package: nginx: installed: matches expectation: [true]
Package: nginx: version: matches expectation: [["1.11.10-1~jessie"]]
Total Duration: 0.012s
Count: 13, Failed: 0, Skipped: 0
INFO: Deleting container

Note: If you’re more of a visual person, there’s a video version of this tutorial at the bottom of this blog post.

Prerequisites

In order to follow along this tutorial, you need to have Docker installed.

Installing our test tool

We’ll be using Goss as the testing tool of choice. The installation is simple and only takes a few seconds.

curl -fsSL https://goss.rocks/install | sh

NOTE: If you are weary of curl | sh , you can install it manually by following the instructions here.

So.. What is Goss?

Goss is a YAML based serverspec alternative tool for validating a server’s configuration. It eases the process of writing tests by allowing the user to generate tests from the current system state. Once the test suite is written they can be executed, waited-on, or served as a health endpoint.

More info can be found on the Goss webpage.

Writing our test

dgoss is a helper tool that comes with Goss to make it extremely easy to write docker tests. Let’s say we run our docker image in the following way:

docker run -p 8080:80 nginx:1.11.10

To start writing our tests we substitute docker run with dgoss edit:

dgoss edit -p 8080:80 nginx:1.11.10

This will run the docker image, and drop us into an interactive shell with Goss installed in the container, you will see an output similar to this:

INFO: Starting docker container
INFO: Container ID: 9468c0c3
INFO: Run goss add/autoadd to add resources

Once in the interactive shell we can start writing our test suite. Paste in the following commands and they will derive tests from the running container’s state:

goss a file /var/log/nginx/access.log /var/log/nginx/error.log
goss a process nginx
goss a port 80
goss a package nginx
goss a http http://localhost
exit

Note: “a” is short for “add” in Goss.

After we exit the container will be deleted, and you will now see a goss.yaml in your current directory that contains the following:

file:
/var/log/nginx/access.log:
exists: true
mode: "0777"
size: 11
owner: root
group: root
linked-to: /dev/stdout
filetype: symlink
contains: []
/var/log/nginx/error.log:
exists: true
mode: "0777"
size: 11
owner: root
group: root
linked-to: /dev/stderr
filetype: symlink
contains: []
package:
nginx:
installed: true
versions:
- 1.11.10-1~jessie
port:
tcp:80:
listening: true
ip:
- 0.0.0.0
process:
nginx:
running: true
http:
http://localhost:
status: 200
allow-insecure: false
no-follow-redirects: false
timeout: 5000
body: []

This can be executed by running:

dgoss run nginx

Modifying our tests by hand

The YAML file we generated in the last section can be written by hand. The dgoss edit command is intended as a helper to ease the process of writing tests. However, in most cases the generated YAML will need to be modified. Let's go ahead and do that..

For the files section, we only care that the log files are symlinked to stdout/stderr, so let’s remove the mode, size, owner, group, and contains checks. Our files section should look as follows:

file:
/var/log/nginx/access.log:
exists: true
linked-to: /dev/stdout
filetype: symlink
/var/log/nginx/error.log:
exists: true
linked-to: /dev/stderr
filetype: symlink

For the http check, let’s remove the https related flags and validate that the “Welcome to nginx!” message appears in the response body:

http:
http://localhost:
status: 200
timeout: 5000
body:
- Welcome to nginx!

Our YAML file should now be 28 lines:

file:
/var/log/nginx/access.log:
exists: true
linked-to: /dev/stdout
filetype: symlink
/var/log/nginx/error.log:
exists: true
linked-to: /dev/stderr
filetype: symlink
package:
nginx:
installed: true
versions:
- 1.11.10-1~jessie
port:
tcp:80:
listening: true
ip:
- 0.0.0.0
process:
nginx:
running: true
http:
http://localhost:
status: 200
timeout: 5000
body:
- Welcome to nginx!

Same as before, executing this is simply:

dgoss run nginx

What’s next?

This tutorial is meant as a quick start showcasing a simple test scenario. For more advanced use cases take see the following resources:

  • Goss — The tool used in this tutorial
  • dgoss — Helper tool packaged with goss, also used in this tutorial
  • dgoss-examples — Repo containing more complex examples of using dgoss to validate docker images
  • Goss manual — Goss documentation

Video version of this tutorial

If you found this article beneficial, please recommend it to others by clicking the heart.