Setting up a Managed Local Terraform Version
--
We use Terraform to provision and manage our infrastructure on AWS. We have some “legacy” terraform code that requires a much earlier version of terraform, but we also started newer projects and require one of the latest versions of terraform. There are some significant differences between the two versions and we wanted to make sure that everyone was using the correct version for the project. We built a way to make sure every terraform
command is run with the correct binary for the project.
Background
Terraform is built on Go and is released as a single binary. You can download and use the Terraform binary directly by downloading from their releases page. Utilizing this knowledge, we decided to use that to keep a consistent version across computers.
The high level setup would look like this:
- Download Terraform binary from the releases page using a specified version
- Setup a reference to that location as the binary execution location
- Use that binary location to execute
terraform
commands
There are other terraform version managers like tfenv, but we didn’t want any engineer to have to install anything. An advantage of this method is that it just works right out of the box (on Mac and Linux) on our developer machines and can easily be run on a Linux server as well if need be without needing to install an extra dependency.
Makefile Setup
We use Makefile
to setup easy commands with built-in defaults for various tasks that we run.
This assumes a that you have a terraform
directory that has a qa
or production
directory within there as the environments. A simple setup.
TERRAFORM_VERSION := 0.11.7
TERRAFORM_LOCATION := .tf
TERRAFORM_BINARY := $(CURDIR)/.tf/terraform
PLATFORM := $(shell uname | tr '[:upper:]' '[:lower:]')# Download the correct terraform version
get-terraform:
@curl -o tf_tmp.zip https://releases.hashicorp.com/terraform/$(TERRAFORM_VERSION)/terraform_$(TERRAFORM_VERSION)_$(PLATFORM)_amd64.zip
@unzip -o -d .tf tf_tmp.zip
@rm tf_tmp.zip# Check if Terraform binary exists, otherwise download it
check-terraform-exists:
@[ ! -f $(TERRAFORM_BINARY) ] && make -s get-terraform || true# Default to QA env
ENV := qa
# Check the terraform version and download if it isn't up to date
tf-version: | check-terraform-exists
ifneq ($(shell $(TERRAFORM_BINARY) version | head -n 1 | cut -d " " -f2 | tr -d v), $(TERRAFORM_VERSION))
@echo "Terraform version is out of date. Downloading correct version..."
@make -s get-terraform
@echo "Terraform binary updated"
else
@echo "Terraform version is up to date..."
endif# Terraform init to a specific environment (make init ENV=qa)
init: | tf-version
@cd terraform/$(ENV) && $(TERRAFORM_BINARY) init# Terraform plan to a specific environment (make plan ENV=qa)
plan: | tf-version
@cd terraform/$(ENV) && $(TERRAFORM_BINARY) plan
# Apply terraform to a specific environment (make apply ENV=qa)
apply: | tf-version
@cd terraform/$(ENV) && $(TERRAFORM_BINARY) apply
Now, this may look like a lot, but it allows the following:
- Allows you to specify terraform version within the
Makefile
- Downloads the binary for the specified platform (tested on MacOS and Linux)
- Utilizes that Terraform binary for commands using
make init
andmake plan
andmake apply
- Allows you to specify a environment to execute against
- Checks if the terraform version you have downloaded locally is up-to-date, otherwise replace it with the version it should be using
Much of this setup can be ported over to other build tools and scripts, it’s just shell commands after all. :-)
If you want to see this in action or try it out, see this example repository.