Trusting Your Software Build — Immutable, Repeatable Build Environments

Having worked in several projects with varying levels of maturity in Continuous Integration / Continuous Delivery, I have experienced that in practically all cases, a green build is a trusted build.

Interestingly, how many software developers have been in a situation where the build “works on my machine” but falls over on another machine? Moreover, most static build servers are maintained by multiple people and have likely existed for long enough to collate a bulk of tooling that is neither necessary nor entirely intended. Then there are developers whom have also been configuring their laptops manually, installing different versions of build tools. For example; Unix-like environments in Windows, 32-bit vs 64-bit JVMs, multiple versions of compilers, and so on. Then raise the topic of a trusted build. If you cannot fully trust your software build, then how much trust can you place in your continuous integration or delivery pipeline?

This post covers some general information on how you can start to trust your software build.

Configuration Management Tools

The real reason for not trusting your software build is because you do not trust your build environment, and the first step towards managing build environments is to employ some sort of configuration management tool. The usual suspects are Ansible, Puppet or Chef. Whilst a very worthwhile activity towards automating setup and maintenance of existing environments, there is still a fundamental shortcoming with this approach — we are provisioning and recycling existing environments. Why is this a problem? Well, configuration over time may stray from the expected (due to manual interventions, updates, etc.); commonly known as Configuration Drift. As well as recycling environments, should one want to parallelize builds in such an environment, the parallel build tasks will be sharing an environment and file system. So back to the question; can we completely trust a build environment managed in this way? More than an unmanaged build environment, but still not entirely.

Isolated and Immutable Build Environments

The goal of a trusted build environment is to create, from scratch, an entire operating environment. This environment will be entirely isolated, immutable, repeatable and short-lived. No residue from previous builds, no configuration leftovers from “that time the server went haywire”. And if we need concurrent builds, then we simply create another instance of this isolated build environment. Voilà! Scalability is inherent!

Getting Started with a Trusted Build

There are many tools and options to choose from in creating such a build environment, and Docker is probably the most well-known and easiest to get started with. If requiring Windows environments then tools like Packer allow us to build Windows images, that can then be run in virtualization tools such as VMWare. In our team we have also been playing with creating custom Chocolatey packages for Windows, so that one can simply run

choco install my-custom-tool

And we can provision our build environments this way. Developers can also leverage these choco packages to install build or test tools on their local work stations.

The next few blog posts will cover these topics in more detail with technical examples of Docker, Packer, Vagrant, and all the other goodies that can be used to help in this area. Stay tuned!!