Journey to Terraform 0.12

Over the past couple of months I’ve been involved in upgrading my favourite automation tool; Terraform, to version 0.12.

I was late to the 0.12 party for a couple of reasons:

  • There were over 110 Terraform states to upgrade, across 3 clouds and 20+ Terraform providers
  • Many of the states shared the same custom modules
  • A couple of Terraform providers took a while to support 0.12
  • Some providers for 0.12 only supported the latest version of the platform it’s managing e.g. Kong API

This does not describe how to upgrade Terraform to 0.12 (the official guide is here: https://www.terraform.io/upgrade-guides/0-12.html), but shares some tips and tricks to speed up the process and minimise impact.

Backup your states

Once you run terraform apply with 0.12 on a state, it cannot go back to 0.11, so ensure you’ve backed up your states. You can save your remote state with:

It is also a good practice to have bucket versioning enabled on your storage bucket (I use at least 10 versions).

Upgrade custom modules

If you’re using many custom modules in your git repository, clone them all into another location i.e. 0.12/ subfolder, and upgrade each one independently.
Yes you can do a terraform init and plan on a module just to validate the syntax:

Specify min version for all providers

If you see the following error message:
Error: Failed to instantiate provider “github” to obtain schema: Incompatible API version with plugin. Plugin version: 4, Client versions: [5]

This indicates that your provider does not support Terraform 0.12.
Many people do not specify a min version for providers, especially the core Terraform providers such as template, http, random, null etc… Upgrade each one and specify a min version e.g.

Upgrade states

TLDR;

You may see some default values have changed or been added to the new provider, add them to your .tf files until you see no changes or they are minor changes and safe to apply.

The 0.12upgrade command creates a versions.tf file which is a quick way to see whether you’ve upgraded this state yet (including in modules).

Some gotchas

The 0.12upgrade does a great job but isn’t going to be 100% accurate. Some common changes are:

var.version reserved
Remove any var.version as it’s now reserved (I’ve had to remove it in lots of modules relying on a version of a helm chart for example)

Count for enabled
A quick fix for the count where it’s used for true/false is to convert it to 1 or 0:
count = var.enabled ? 1 : 0

Quotes
Some fields in resources need quotes as Terraform thinks it’s a variable or resource property, when it’s not and consequently removes the quotes. In this example credentials.json needs to be quoted

Lookups
If you get the error message “Blocks of type “default” are not expected here. Did you mean to define argument default?”.

Lists have changed with 0.12 and are much more powerful, a shortcut to keep it working is to just specify type = any.

Happy terraforming !

Infrastructure automation with Terraform

TerraformHashicorp, the cool guys behind Vagrant, Packer etc… have done it again and come up with a simple way build, modify and destroy cloud infrastructure. It is pure infrastructure as code which can be version controlled. But the best part is that it can work with many cloud platforms: AWS, Google Cloud, Digital Ocean, Heroku etc…

Getting Started

The official documentation can be found here.

Download the zip package from http://www.terraform.io/downloads.html for your O.S., extract and move the executables into your /usr/local/bin (or add the folder to your $PATH).

Verify the installation by executing:

We‘ll be using AWS as the provider so you will need an access and secret key for your user account.

Create a folder where you will keep all your .tf files. You can later add this folder to Git version control.

Provisioning a single EC2 instance

Create a file called web-instance.tf with the following:

The provider line tells Terraform to use the aws provider using the keys and region provided.
The aws_instance instructs Terraform to create a instance with a tag “web” using the Ubuntu 14.04 LTS AMI.

Before building infrastructure Terraform can give you a preview of the changes it will apply to the infrastructure:

It uses Git diff syntaxing to show the differences with the current state of the infrastructure. Currently there’s no aws_instance tagged “web”, hence the line has a +
The “computed” values means that they will be known after the resource has been created.

To apply the .tf run:

Now check the AWS console, the instance has successfully been created !

The terraform.tfstate file which gets generated is very important as it contains the current state of the infrastructure in AWS. For this reason it’s important to version control it in Git if others are working on the infrastructure (not at the same time).

Modifying the infrastructure

Edit your web-instance.tf file and changed the instance type from t2.micro to t2.small then check what will change:

The value for instance_type has changed, apply the new changes:

Instead of stopping the existing instance and upscaling it, it destroys and creates a new aws_instance resource.

Destroying the infrastructure

Before destroying infrastructure, Terraform needs to generate a destroy plan which lists the resources to destroy, to a file here named destroy.tplan

The line with – confirms that the aws_instance resource tagged web will be destroyed, lets apply the destruction plan:

Provisioning a multi-tiered VPC

Terraform can provision a VPC using most of the available VPC resources, except a few which are missing.

Here we provision 2 web instances, 2 application instances and a nat instance within 2 tier VPC, complete with appropriate security groups, load balancers, route tables, internet gateway, elastic IP etc…

The gist can be viewed here.

Conclusion

Terraform is an use out of the box ready and easy to use tool to build infrastructure using only a couple of lines. It’s very practical to quickly build a proof of concept infrastructure.

Using the AWS provider, it’s missing a couple of resources such as Elastic Network Interfaces, Access Control Lists, Security Groups egress rules, VPC DHCP options plus it does not support User Data (it can only execute remote ssh commands). However at version 0.2.1 it is still very early days and no doubt we will be seeing lots of improvements to Terraform in the future !