Skip to content

Terraform: The Basics

Install

Let's start with something overly obvious: To run Terraform, you need it to be installed on your system.

curl https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip | funzip > /usr/local/bin
wget https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip -O - | funzip > /usr/local/bin
brew install terraform

Prepare

We will focus on using Terraform in Google Cloud Platform (GCP). Terraform needs a Service Account to communicate with GCP.

Create a Servie account with adequate permissions IAM > Service accounts and create a JSON credentials file for it.

cat provider.tf

provider "google" {
 credentials = "${file("/path/to/credentials-file.json")}"
 project     = "your-project-id"
 region      = "us-central-1"
}

Now you can use your credentials file in Terraffrom provider definition along with project id and region name. You could set that in your CLI environment instead of setting credentials field in provider section as well.

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/credentials-file.json"

Initialize terraform

terraform init

This will download provider plugin, modules (if any) etc.

We are now ready to Terraform GCP!

Terraform GCP

Our first instance.

Add below content in main.tf file.

cat main.tf

// Terraform plugin for creating random ids
resource "random_id" "instance_id" {
 byte_length = 8
}

// A single Google Cloud Engine instance
resource "google_compute_instance" "default" {
 name         = "first-vm-${random_id.instance_id.hex}"
 machine_type = "f1-micro"
 zone         = "us-central1-a"

 boot_disk {
   initialize_params {
     image = "debian-cloud/debian-9"
   }
 }

 network_interface {
   network = "default"

   access_config {
     // Include this section to give the VM an external ip address
   }
 }
}

Run

terraform plan

Umm.. Did something go wrong?

The problem is, we are using random_id resource there (It's a good practice to randomize resource names). This needs random plugin which Terraform needs to pull down. So run terraform init once again.

Now, terraform plan will show you a summary of what to be done. Which resources to be created, which to be deleted and which to be simply changed. In our case, it's just creating the random id and the actual vm instance, because ours is a fresh start.

We use terraform apply to apply a plan and have the resources created/deleted/changed.

terraform plan -out=my-plan.out
terraform apply my-plan.out

This will create an instance on GCP for us. The rest is pretty much the same except you have to spend time on terraform docs (and stack overflow and github issues, on blogs, in github reading code and on and on but I digress)

Happy terraforming!

Parameterize

It's an amazing feeling when you can describe something in code (Configuration! Let's be real) and have it done for you automatically. But there's more to it. You can parameterize and reuse what you just wrote.

For example, if you want to have an instance of different type and in a different zone, do we just copy paste and edit the fields?

Well.. instead of that, we can use this ground breaking concept called..

..variables!

cat variables.tf

variable "gcp_machine_type" {
  description = "Your GCP project ID"
}

variable "gcp_region_zone" {
  description = "The GCP zone to deploy instance"
}

Now to use these variables, update your main.tf as follows.

 machine_type = "${var.gcp_machine_type}"
 zone         = "${var.gcp_region_zone}"

Now we run terraform plan and terraform apply and be done with it. Not so fast! Terraform doesn't know what to use for gcp_project_id and gcp_region. Try running terraform plan. It'll ask us what to use for the varibales.

This is not gonna be fun when we have more variabales and/or when we run it dozens of times. There are two things to do.

  1. Set a default to varibale.
  2. Provide a .tfvars file with the vaules.

See below for an example of setting a default.

variable "gcp_region_zone" {
  description = "The GCP region to deploy resources"
  default     = "asia-southeast1-a"
}

That's easy.

Now let's look at .tfvars

cat settings.tfvars

gcp_machine_type = "f1-micro"

gcp_region_zone = "asia-southeast1-a"

To incoporate our shiny new settings.tfvars file in Terraform, run plan as follows.

terraform plan -out=my-plan.out -var-file=settings.tfvars

Tip

If you name your .tfvars file settings.auto.tfvars, terraform will automatically pick it up. (It doesn't have to be named settings. It could be what-i-fancy.auto.tfvars and nobody cares.)

We are almost all ready to Terraform everything. Before we wrap up, there's something very importnant to cover. That is Terraform Modules.

Modules

Terraform modules allows code reuse of insane scale. For example, if you want to deploy a Consul backed Vault cluster, There's a module for it. You can find more modules at Terraform module registry.

Using readymade modules is not the only appeal in Terraform modules. We can make our own modules to make our lives easier. This Hashiconf '17 talk by Gruntwork co-founder is a great starting point.