Continuous Delivery with Thoughtworks Go and Docker

I’m finding Thoughtworks Go and Docker to be a great combination for managing the building, testing, and deploying of applications. A nice bonus is that both of these tools are completely free and OSS.

Go provides an attractive GUI that lets you see your build and deployment history or trigger manual deployments. When did you last deploy to live? what git commit did you deploy? who deployed it? Go helps you to answer all of these questions very easily.

When it comes to running tasks, like tests, delegating to Docker removes a whole category of installation and configuration headaches. All I need to install on a Go agent is Docker — any dependencies needed by an application are installed within a container. You never need to touch the host OS.

If you’re not familiar with Docker, just think of it as very lightweight virtualisation for now

Automating Your Build/Deployment Pipeline with Go

Deploying code should be easy, and knowing what code to deploy should be as well. If you’re checking out git branches on your local machine and copying files over SSH, you are open to all kinds of human error. Thoughtworks Go is a free tool that let’s you eliminate these problems.

With Go, you set up custom pipelines that represent your process. You can see in the image below that my process is to build and test the application (Build_and_Test) each time there is a change to the git repository. Upon success, where all tests passed, there is an automatic deployment to the integration environment (Int_Deploy).

Go’s GUI makes it easy for you to make the right decision

The triple arrow symbol between the Build_and_test and Int_Deploy stages indicates an automatic trigger. But if you look between Int_Deploy and UAT_Deploy and Prd_Deploy you will see a different symbol — an arrow either side of a line. This indicates that you have to manually trigger the next step.

So looking again at the build pipeline, you can visually discern that our process is:

  1. auto build and test (on push to git)
  2. auto deploy to Integration
  3. manually deploy to UAT
  4. manually deploy to Production

Guaranteed to Deploy the Right Code

My build pipeline in GO ensures that its very difficult for me to deploy the wrong code. All I have to do is look for the last green bar under “UAT_Deploy” and I know that code is on UAT. This means I just need to click the button to deploy it to production.

If I want to know which git commit is running, I just look at the left hand column of a row as shown below. It tells me the git commit number, who commited, and shows the commit message:

Go shows you which git commit it is currently processing

Not all deploys are pushing new code, though. Sometimes you need to rollback — unfortunately Go doesn’t stop you from deploying bugs. But it’s OSS, accepts pull requests, and just waiting for you to create that plugin.

There are two options I’ve found for rolling back. Option 1 is to click the “re-run” symbol below the last deploy that you know is safe — the one you want to rollback to. This image belows shows how I could roll back to a previous “Prd_Deploy” using this technique.

Rerun a previous deploy to quickly rollback to it

Another option for rolling back is to trigger the entire pipeline again. You create a new row in the GUI after choosing a specific git commit to run. Using this option, the rolled-back-to code will be deployed to all environments, whereas with the first approach the code with the bug would still be on UAT.

Build, Test, and Deploy — All You Need Install is Docker

At each stage in the pipeline, you have to instruct Go to execute a task, like running your tests. You also have to tell it how to do this, such as run a rakefile. I’ve got a better idea — tell it to run a Docker container.

The big benefit of using Docker is that you only have to install one piece of software on your Go agents (the nodes that actually run the tasks). You can configure all your dependencies inside Docker images.

Below is an example of where I tell go to run a shell script that starts a Docker container to build and test my Scala application. Inside that container is Scala, it’s build tool, an instance of Elasticsearch and an instance of Redis, all for my tests. None of these things are installed on the Go agent.

Telling Go to run a shell script that runs a Docker container

Note: This shell script lives with the source code of the application in the git repository. This means it is accessible to Go. The “working directory” value is pointing to a path inside the git repository.

This makes life very easy. You could have Go containers running ruby tests, java tests, deploying with Capistrano.. all with different versions, all running on the same Go agents. And still, nothing has to be installed on the Go agents except Docker.

Advanced Features if You Need Them

I’ve only shown the most fundamental parts of Thoughtworks Go and Docker. Each of them has many more features. So if you’re thinking that these tools might not be able to do what you want, I’d be very surprised if they can’t.

Remember as well, they are both open source. If you really need a feature, you can submit a pull request. I’m sure we will continue to see both of these tools enhanced by such community efforts over the years.

--

--

Nick Tune
Strategy, Architecture, Continuous Delivery, and DDD

Principal Consultant @ Empathy Software and author of Architecture Modernization (Manning)