Some languages have environment or version managers such as RVM for Ruby, NVM for Node, or even Rackspace's DVM for Docker.
It's highly recommended to lock the Terraform version, so everyone in the team uses the same version, and updates can be painlessly handled. To do that, I suggest using a Terraform container, so we'll use here the one I use myself: sjourdan/terraform:<version>
(from https://github.com/sjourdan/terraform-docker). But I understand replacing the simple terraform
command by something such as docker run -it --rm -v `pwd`:/data sjourdan/terraform:0.7.3
can feel not so appealing. That's why we can use a common Makefile
for each project using Terraform.
Using a common entry point for manipulating the infrastructure code helps a lot of sharing practices, enforcing policies, and integrating third-party services such as CI systems.
To step through this recipe, you will need the following:
Let's begin by setting the Terraform version we want to use in a Makefile so it will be easy to manipulate for updates in the future:
TERRAFORM_VERSION = 0.7.3
Let's now create a TERRAFORM_BIN
variable that will include the full Docker command, plus share our local folder:
TERRAFORM_BIN = docker run -it --rm -v "$(PWD)":/data sjourdan/terraform:$(TERRAFORM_VERSION)
I like auto-documenting my Makefile, and I propose a popular technique: make
by default calls make help
, which in turn parses the Makefile
for comments, and displays them. That way, I can choose what to output by simply adding a comment. Here's how it works:
.DEFAULT_GOAL := help help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " 33[36m%-30s 33[0m %s ", $$1, $$2}'
Now simply use this feature to create an entry for the validation and formatting from the previous recipe:
validate: terraform-fmt terraform-validate ## Validate syntax and format terraform-fmt: $(TERRAFORM_BIN) fmt -list terraform-validate: $(TERRAFORM_BIN) validate
If you simply type make
, you'll get an automatic help:
$ make validate Validate syntax and format
Now, a simple make validate
will both validate the syntax and format the code.
It would be great to have the plan
and apply
commands as well, and if you followed the recipe on environment management with Terraform, that would be awesome if it worked right from the Makefile
, we'd save a lot of time.
Start by creating the Makefile
main "help" entries:
plan: terraform-validate terraform-plan ## Plan changes apply: terraform-validate terraform-apply ## Apply Changes
Let's check for an environment variable named env
, passed at make
execution (such as make plan env=staging
), and returns an error if not set:
ifndef env getenv=$(error var:"env=" is not set) else getenv=$(env) endif
Now we can write what terraform-plan
and terraform-apply
are exactly running, with isolated Terraform states and environments:
terraform-plan: $(TERRAFORM_BIN) plan -state=$(call getenv).tfstate -var environment=$(call getenv) terraform-apply: $(TERRAFORM_BIN) apply -state=$(call getenv).tfstate -var environment=$(call getenv)
By the way, you can add support for environments to our previous terraform-validate
example:
terraform-validate: $(TERRAFORM_BIN) validate -var environment=$(call getenv)
Add as many features as you want to your project's Makefile
; you'll soon realize this simple tool helps so much.
For example, I always add a make destroy
command, so I can easily destroy a test infrastructure (be careful though!):
destroy: terraform-destroy ## Destroy (careful!) terraform-destroy: $(TERRAFORM_BIN) destroy -state=$(call getenv).tfstate -var environment=$(call getenv)
Our Makefile now looks like this:
$ make apply Apply Changes destroy Destroy (careful!) plan Plan changes validate Validate syntax and format
Also, it can be used like this:
$ make plan env=staging $ make apply env=staging
3.139.103.204