How to unit test.. a server with goss

I’ve been looking through the latest Technology Radar issue and here’s what I found in its new Techniques section: “TDD’ing containers”. Wow. Mentally, I’m not yet ready to connect TDD to containers, but I took a look at the tools used for that, and those are quite interesting.

The first one is serverspec, which allows running BDD-like tests against local or remote servers or containers. It looks pretty solid, supports multiple OSs and its only downside (for me) is that serverspec is written in Ruby and therefore doesn’t really fit in the stack I normally work with.

The other one – goss – leaves an impression of a multitool, which usually worries me, but here… I’m kind of curious, so let’s have a look.

What is goss for

goss is a tool that checks if current server satisfies certain configuration. It’s that simple. “Certain configuration” here can mean different things, starting from whether specified process is installed and running, necessary ports are open and user accounts are set, and ending with local or remote URLs responding with expected content.

Quick example

I’ve prepared a trivial Vagrantfile to quickly spin up a VM with goss installed, so I can play with it in safe disposable environment:

Creating a server specification file

Like many tools nowadays, goss keeps its configurations (server or container specs) in YAML files. I could create one from scratch, but what’s cool I actually can do that semi-automatically by asking goss to scan particular feature of current machine and add it to config file.

For instance, my current host has user ubuntusshd service and ports 80 and 443 being closed. I think that’s a perfect configuration and all of my other servers should follow it. To check if that’s currently the case, I can ask goss to add these features’ states to config file, then bring it to all other servers (can’t test them remotely) and call goss validate.

I had to clean up resulting file a little bit, as I don’t care what groups ubuntu user belongs to, or which network interfaces’ ports we’re going to test, so resulting goss.yaml started to look like this:

Testing if server matches specification

That couldn’t have been any simpler:

Testing if docker container matches specification

goss comes with evil-twin brother called dgoss, which knows how to test Docker containers. It’s easy to remember how to use it:

  • docker run ubuntu sleep 1 will launch Docker container using latest ubuntu image, which will sleep for 1 second before shutting down, whereas
  • dgoss run ubuntu sleep 1 will test such container.

In my case dgoss shows that native ubuntu image fails the test:

Because both dgoss and goss‘s exit codes reflect whether the test was successful or not, it’s quite easy to connect them to CI and validate, for instance, if Dockerfiles still produce what they supposed to.

Interesting side-effects

There’s nothing particularly fancy in testing server configurations, so here’re few very interesting side-effects instead.

Firstly, goss validate command can wait:

This command will try to validate server every 5 seconds until it succeeds or 1m timeout. What it means for us is we could postpone, for example, Docker’s entry point commands until container dependences become ready:

Secondly, we could use goss for Docker health checks or Kubernetes liveness or readiness probes. I used to test with curl if container’s web service is still responding:

Instead, I could add more validation steps and use goss :

In fact, it doesn’t have to be executing goss validate all the time. goss serve can start a small web service with health check endpoint – http://127.0.0.1:8080/healthz. This URL would respond with test results and 200 OK http code when everything’s fine, and 503 Service Unavailable when it’s not. What’s cool both Docker and Kubernetes know how to interpret these status codes, so they’d be able to work with this endpoint right away.

Conclusion

Even though goss seems like a nice tool for validating servers and containers configuration, I’m more enthusiastic about using it as a Kubernetes or Docker health check provider. Seriously, I can see so many things to put into goss.yaml file, so e.g. Kubernetes knows when it’s OK to route incoming traffic to the pod, or it’s time to restart it. Of cause, all of that could be achieved by relatively simple bash script. But that’s one more kind of wheel we don’t have to reinvent anymore.

Leave a Reply

Your email address will not be published. Required fields are marked *