Treating Your Terraform like an Application: Part 1
Why Terraform in a Docker Container?
Part One in a two-part series about running Terraform in Docker
What is Terraform?
Terraform is an amazing tool; it allows infrastructure to be created in an idempotent and programmatic manner. Terraform allows for reusable, cloud agnostic, infrastructure modules to be created and written. It allows for conditional environmental infrastructure allowing for easy and repeatable promotion through stages. Using Terraform to provision infrastructure is a great start to Infrastructure as Code (IaC).
What is Docker?
Docker is all the rage these days, and if you don’t know what Docker is or containers do, then I recommend you read up here. However, for a short description from the Docker site:
“A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another. A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.”
Docker provides a method of packaging a complete application. This includes runtimes and dependencies. It allows you to ship applications and have confidence in the running result. While this result can be achieved with both baremetal and virtual machines, a docker container is far, far smaller than is feasible to achieve with direct OS layers, more portable as it can be interpreted by any docker agent rather than relying on the type of virtualization layer, and can be run at a far higher density due to its small footprint.
Why Should I Put My Terraform in a Docker Container?
Now that we’ve covered what Docker and Terraform are, why should you put your Terraform in, and run it from, a Docker container?
In my experience putting your Terraform in a Docker container allows for:
- Terraform to fit into your already created artifact management procedures.
- Properly versioned infrastructure.
- Duplicate environments based on versioned infrastructure.
- Standardization and Portability of deployment environments.
Let’s cover them one by one.
Artifact Management Procedures
One of the big benefits of putting Terraform in a Docker container is that it can now be treated like any other artifact. It can be stored, retained, and managed just like your application’s code/artifacts. Whether for compliance, legal, or just standardization of process, putting your Terraform in Docker simplifies how completed and tested infrastructure is stored.
While a GitHub repo with source code can always be versioned, that GitHub repo won’t contain all the dependencies of running Terraform, nor is it advisable to store binaries and artifacts in Github. Storage of large and small artifacts is better suited to an artifact storage solution like Artifactory, Dockerhub, Nexus, etc. By placing your Terraform in a container you allow for the dependencies to be downloaded and contained alongside it. This allows you to roll back in the event of a failure.
If you’ve written new Terraform, rolled it out, and had something fail, you can simply do a
docker run myteams/terraform:<version> apply and roll back all your changes to a known good state.
Duplicate Environments Based on Versioning
In an ideal world, every one of your teams/customers would use the exact same application version and architecture. In the real world, however, that’s not the case. Being able to run and deploy entire products with a single Docker run command, based on a version of code, gives you all the abstraction of AWS OpsWorks or Elastic Beanstalk without using a hosted service (or, if you need to extend across cloud providers, can’t use a hosted product, or need a version of a dependency not supported). Each customer could have an environment spun up by simply running
docker run myteams/terraform:<version> apply and providing some arguments. The same version can be deployed multiple times with only the arguments or environment variables changing. Roll-outs and roll-backs can be done across customer environments with a single deployment because the only difference will be variables.
Standardization and Portability of Deployments
If you are like most large enterprises, your Terraform is probably deployed using Jenkins or another CICD system. These are great for a lot of things, but one big problem is that no matter how highly available and resilient your CICD system is, it will eventually go down. And when it goes down, it’s a definite possibility that the rest of your infrastructure will also have issues. Having the ability to execute your Terraform locally via Docker means you can guarantee it is separate from your CICD system and can still deploy infrastructure.
Putting your Terraform in a Docker container also means you can guarantee that the same commands are being run when you develop locally vs. when Jenkins runs your deploy job. As previously discussed, it means the same dependencies are available and that you can have confidence in what is being run/deployed/downloaded. If you need to transition to a different CICD server you can simply pass it the container and command and be confident it works there too.
Terraform allows you to define your infrastructure in a repeatable, reusable, and automatic manner. It prevents configuration drift, allows you to synchronize changes, and stand up entire environments with no manual changes.
Docker allows you to build reusable, repeatable, portable, tiny self contained images. These images can be easily moved between environments with variables abstracted away. These images can be run multiple times with the same result.
Combining Terraform and Docker means you get infrastructure that is repeatable, reusable, automatic, portable, and self-contained. In the event of a roll-out or roll-back, simply running the Docker container is enough to put infrastructure in a given state. It prevents issues in the commands, proxies, or other changes in the CICD system from preventing roll-out or roll-back.
This is, in my experience, especially useful when a production system or environment is down and the team is facing a stressful situation. Lowering the amount of information to remember by having version infrastructure artifacts for roll-out lifts just a few more things off the mind, allowing for concentration on other aspects of a situation.
In the next post, I’ll cover how to actually dockerize Terraform because there are a few things that you should be aware of during this process.
These opinions are those of the author. Unless noted otherwise in this post, Capital One is not affiliated with, nor is it endorsed by any of the companies mentioned. All trademarks and other intellectual property used or displayed are the ownership of their respective owners. This article is © 2019 Capital One.