What I Learned at Work this Week: Terraform Basics

Mike Diaz
5 min readMay 2, 2022

--

Picture unrelated

Sometimes at work, I get requests that I can “freestyle.” I don’t bother to consult any documentation because I know how all the pieces fit together and even if I’m wrong about the way I think my code will work, I know how to debug locally and in production. These are my favorite kinds of requests because it feels good to be competent at what you do.

And then there are the…other type of requests. The ones where I have to read the documentation twice because none of it makes sense to me and I don’t want to mess this up because I won’t know how to fix it if I do. Terraform falls into that bucket. I mean…what even is this?

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.27"
}
}
required_version = ">= 0.14.9"
}
provider "aws" {
profile = "default"
region = "us-west-2"
}
resource "aws_instance" "app_server" {
ami = "ami-830c94e3"
instance_type = "t2.micro"
tags = {
Name = "ExampleAppServerInstance"
}
}

This weekend, I got my knowledge of Terraform from about 0.1/10 to 0.6/10. I still find it difficult to follow, but let’s review what I was able to process:

What is Terraform?

To quote the docs:

HashiCorp Terraform is an infrastructure as code tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share.

This is the first sentence in the Terraform documentation and a perfect encapsulation of what makes it so impenetrable. What does this mean??

  • infrastructure as code: In this case, the infrastructure is the series of platforms and tools we use to make our code work. If we’re hosting on AWS, that’s part of our infrastructure. If we use Kubernetes to run our code, that’s part of our infrastructure. If we use Datadog to monitor our performance, that’s part of our infrastructure too. Most infrastructure services have unique user interfaces that let us set up and customize our uses, but we can also use Terraform to set preferences by communicating with their APIs. So rather than using their UI, we’re writing code with Terraform to manage our infrastructure.
  • cloud and on-prem resources: This just means that we can manage tools whether they’re on a cloud service like AWS or on our own physical servers (on the premises). At least in my case, most of what I do is on the cloud.
  • human-readable configuration files that you can version, reuse, and share: Terraform is written in code that I think is hard to understand, but it’s readable compared to, say a Kinesis protobuf. Consider the example above — we don’t know what all these values mean yet, but we can take a guess about some variables like required_version, region, or instance_type.

The docs break the Terraform workflow into three steps:

  1. Write: develop the instructions for interacting with your provider APIs.
  2. Plan: Terraform creates an execution plan based on those instructions and prints the implications. This is sort of a testing step where you have a chance to approve the logic or go back and change it.
  3. Apply: If you submit after your plan has run, your changes will be applied!

Breaking down the example

Understanding the purpose of Terraform has been a big hurdle for me since I’m new to most infrastructure concepts. Now that we have a slightly better understanding of that realm, let’s look at the sample from HashiCorp’s getting started documentation.

The code in question would be placed in a file called main.tf. If you’re following along at home, it won’t work unless you also go through the AWS credentials setup detailed in the doc. Naturally, we can’t provision a resource on AWS unless we have an account and provide credentials.

The code starts with a terraform block:

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.27"
}
}

required_version = ">= 0.14.9"
}

We’re declaring which service providers we’ll be working with here and providing details about how they’ll be implemented. This module will be provisioning AWS version 3.27 (~> means the rightmost value can increment, so 3.30 would work but 4.01 would not). source defines an optional hostname, a namespace, and the provider type, which comes from the HashiCorp Registry. As far as I understand, this is just another way of specifying the AWS. requred_version refers to Terraform rather than AWS specifically.

Next we have the providers block:

provider "aws" {
profile = "default"
region = "us-west-2"
}

Earlier, we specified that we want to use AWS, and now we’re configuring it. default works as a value for profile because it was set up earlier in the tutorial with our credentials. region specifies where we’re using our resources since AWS has multiple server locations. It’s possible to provide multiple provider blocks if we’re using multiple resources. What is a resource? There’s a block for that:

resource "aws_instance" "app_server" {
ami = "ami-830c94e3"
instance_type = "t2.micro"
tags = {
Name = "ExampleAppServerInstance"
}
}

The resources block is used to define components of our infrastructure. In this case, the component is the actual EC2 instance that would be housing our data. The strings after resource, aws_instance and app_server, are the resource type and resource name, respectively. The values inside the block are specific to the resource type. I know very little about EC2 configuration, so I’ll just quote the documentation here:

For your EC2 instance, the example configuration sets the AMI ID to an Ubuntu image, and the instance type to t2.micro, which qualifies for AWS’ free tier.

We’ve specified an image and chosen an instance type that won’t cost us anything since this is just a practice sample. Finally, we can apply tags to our resource, in this case a Name.

The power of Terraform

This post scratches less of the surface than I usually do, partly because I happened to have less time to write this week. But it’s also fairly shallow because I am a virtual novice in this concept and it’s difficult for me to understand off the bat. So if reading this didn’t teach you anything new, you can use it as a reminder that, when things are difficult, making even a small amount of progress is monumental, and it sets you up for larger successes in the future!

Sources

Additional Resources

--

--

Mike Diaz
Mike Diaz

Responses (1)