==========================
== Zhuo Hong Wei's Blog ==
==========================
Any and everything

Learning Terraform

Recently I have been picking up Terraform on the job. I love the idea of Infrastructure as Code where all the resources are described in files that are versioned like regular code.

In this post, I am attempting to do a brain dump of what I have learned so far.

In short, I would describe Terraform as an IAC tool that lets you author files (.tf extension) that describes your infrastructure and helps you to manage (apply, destroy) the infrastructure state.

Terraform files

Terraform files have the .tf extension. Most commonly we see the following file structure (this could differ, for example on a larger or more complex project),

  • variables.tf
  • main.tf
  • outputs.tf

I think of the collection of files like a complete program. variables.tf being the input, main.tf being the bulk of the program, and outputs.tf being as it is named, the output. The difference is that the “bulk of the program” here is a list of providers and resources.

Variables

Variables are input parameters that can have validation constraints and default values. These defaults can be overridden using another file terraform.tfvars or supplied directly at the command line when running terraform apply (the command to ask Terraform to process the collection of .tf files).

Example of a variable:

variable "container_name" {
   type = string
   default = "my_default_container_name"
   validation {
     condition = <some condition on var.container_name> 
     error_message = "Name must be at least x characters in length."
   }
}

This variable above can then be referenced as var.container_name in main.tf as shown next.

Providers and resources

In main.tf, we indicate the providers and resources.

Providers

Examples of providers

  • AWS
  • GCP
  • Azure
  • Docker

Sample code for specifying docker provider (from terrafom docker provider docs).

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "2.14.0"
    }
  }
}

provider "docker" {
  # options to customize provider
}

Resources

Examples of resources

  • AWS EC2 Instance
  • Docker image
  • AWS SQS Queue

Sample code for specifying docker image and container resources.

# Pulls the image
resource "docker_image" "ubuntu" {
  name = "ubuntu:latest"
}

# Create a container
resource "docker_container" "foo" {
  image = docker_image.ubuntu.latest
  name  = var.container_name
}

Notice how var.container_name is used here.

Outputs

Following our example above, an example output can be the external port of the container,

output "ext_port" {
  value = docker_container.foo.ports[0].external
}

Normally, outputs could be values that are available after running terraform apply and when the resources are created (e.g. the image is pulled and the container is started).

Common commands

  • terraform plan - tells terraform to generate a plan of what it would do after processing the .tf files in the directory.

  • terraform apply - process the .tf files, prints the changes that will take place, prompts for confirmation and actually applies the changes. To skip the prompt, add --auto-approve flag. After apply is run, a .tfstate file is generated in the same directory (when no backend is configured). This stores the state of the infrastructure and can be shown with terraform state list. If a backend is configured, the state will be stored on the configured backend. This can be Terraform Enterprise, Terraform Cloud or even a custom backend.

  • terraform destroy - destroys the infrastructure, cleans up all the resources.

  • terraform output - shows the outputs since the last apply.