It argues that we should aim to reduce gaps between development and production to increase software quality and velocity. Every gap, be it between people, time or computing environments, adds friction.

One way this commonly manifests is that code “works for me!” on your laptop, but doesn’t start on your team mate’s without extra work. The worst case scenario is that this code is deployed and doesn’t work in production, taking the service down.

This friction can add up to significant time over the lifecycle of software. In the above scenario you and your fellow Developers are spending precious time futzing with your laptop environment, and your fellow DevOps engineers are getting paged because the service is down.

Dev/Prod Parity is an aspiration goal in Twelve Factor, but it’s actually possible to achieve with Docker Images and Containers.

What Parity?

A very common setup is Homebrew for development on a Mac laptop, CircleCI for testing and Heroku for production. With these systems, it’s hard to know, let alone guarantee, what version of Node.js, ImageMagick and Postgres are used in each environment.

Laptop, CI Service, and Production Service Incompatibility Matrix

It’s not impossible to set it all up, but there are pitfalls.

You need to:

Maintain good documentation and scripts in the app codebase to help maintain a Homebrew environment

Wrangle a circle.yml file, and SSH in to failed test runners to figure out what packages to install to get the test environment running

Understand what the Heroku Buildpacks and Runtime add to build and run your app in production

Add hooks to your code base to turn functions off or on in development, testing and production

Once it works, it’s smooth sailing. Until you want to upgrade Ruby, or add PhantomJS for web acceptance testing, or Homebrew packages change, or…

Parity Begins in Development With Containers

Containerization technology, made accessible by Docker, offers a better way.

First, install the fantastic Docker for Mac to get a Docker environment running on your laptop. This app is practically magic, and offers a fast Linux environment on your Mac laptop.

Next, put in some effort to “Dockerize” your app. The goal is to boot your app with a single command: docker-compose up or convox start. This involves writing a Dockerfile and a docker-compose.yml file.

Apps that already follow the Twelve Factor Methodology aren’t too hard to get into shape.

First, you need to describe each process in your Procfile as a “Service” in docker-compose.yml. You also need to add a Service for any database your app uses like Postgres or Redis. This frees you from needing to use anything in Homebrew for development.

Next, you need write a Dockerfile that can build and run your app. You need to pick a base operating system, add system dependencies, then add a few more commands to install the language packages your app uses.

I recommend using Ubuntu 16.04. Ubuntu 16.04 makes it easy to get the latest Node.JS, Ruby, Python, and PHP system packages. It is a “Long Term Support” distribution that will receive security updates through 2021. This is another huge advantage of Docker: we are no longer constrained by the limited CircleCI and Heroku operating system choices.

If it doesn’t, you’ll need a bit more tweaks to your Dockerfile and docker-compose.yml. You might be missing a few system dependences or environment your tests need.

That effort we put in before is paying off big time. There is little to no configuration needed to run tests. And now every team member can run tests on their laptop with a single command. No Homebrew required!

Test Strategies

If the “Dockerized” app runs on a Docker for Mac environment with a single command, it will certainly run on any test service that supports Docker. There are many:

There are almost too many strategies here! We will have to explore the pros and cons of these approaches in future post.

But you can be confident that you’ll be able to run your app in the cloud, again with little to no extra configuration.

Conclusion

Dev/Prod parity is a desirable goal and is possible with Docker Images and Containers.

Put in the work to write a Dockerfile and docker-compose.yml file that works on Docker for Mac, and you have unlocked many paths to test your app and run it in production with little to no additional configuration.

This will increase software quality and velocity, and pay big dividends over the lifetime of the software.

What do you think? Are you already enjoying dev/test/prod parity? Is Docker part of your success? If not, how do you plan to get there?