3 Terraform features to help you refactor your infrastructure effortlessly

Ever created an app, like a website? You create the app and get everything working. But when you go to make a change the thought scares you to death.

Does this sound like you? I’ve been in that very same position, too. Writing code that’s flexible and malleable to change isn’t easy. When it comes to writing infrastructure that’s flexible that’s where a tool like Terraform can help us out.

If you’re not already familiar with Terraform, don’t worry, you’re in safe hands! Terraform is an Infrastructure as Code  tool with some awesome features that allow us to write infrastructure code that’s flexible to change.

By the end of this article, you’ll understand what Terraform is, why it’s a great first infrastructure-as-code tool to learn and how the main features help you to write infrastructure that’s easy to refactor. 

Why is refactor-able infrastructure useful?

Just as with our code, requirements for our infrastructure will change over time. For example, we might deploy a certain number of servers, capable of servicing a number of requests. But as demand increases for our application our infrastructure might need to scale too.

Whatever the reason for the change in our infrastructure it’s essential that the software we create is flexible to adapt to the changes that new demands bring. A couple of ways we ensure code is always in a malleable state is with certain techniques. We can utilise abstractions that loosely couple our services. We can ensure that we thoroughly test our applications. The more confidence we have in our tests the more aggressively we can make changes.

But — how do we apply these same concepts of having flexible, agile software to infrastructure as well as code? Well, I’ve recently spent quite a bit of time working with and writing Terraform and have been absolutely loving some of it’s features that allow us to write flexible infrastructure as code, and I want to share these with you today!

An introduction to Terraform

Before we get into some of the features of Terraform you’ll need to know a little about the Terraform theory — so let’s talk about what Terraform is, how it works and why you should care!

Let’s start with a definition:

Terraform is a stand-alone command-line, infrastructure-as-code tool.

Wow — that was a mouth-full, let’s me break that down for you…

Note: If you’re shaky on infrastructure, check out this previous article for an intro to infrastructure and infrastructure-as-code.

Terraform is a command-line tool. With Terraform you write infrastructure-as-code and then execute a command to run it. The command runs on your computer directly, or on a build server. Terraform doesn’t typically run on the cloud. I’m stressing this point that terraform is not ran on the cloud because it explains a lot of Terraform’s nuances (more on this later).

Terraform is also standalone because (unlike many of its competitors) it has no ties to a particular cloud provider or service. Terraform can be used to provision infrastructure on GCP, AWS and many other services. Unlike some other infrastructure-as-code tools like CloudFormation which are tied to AWS services (we’ll come back to this point too!)

With Terraform you declare the desired state of your infrastructure as code and then Terraform performs quite a lot of magic to move your existing infrastructure to the new described state.

Okay — that all seems kinda complex… but in order to bring everything to life we’re going to talk through how Terraform works in much more detail. So stick with it, I promise at the end it’ll be worth it!

How does Terraform work?

To understand how Terraform works in a more detailed way we need to look at two key concepts:

  1. Terraform State
  2. Terraform Planning and Terraform Applying

Let’s do that now!

Terraform State

The most important concept to know about Terraform is the idea of state.

To understand Terraform state we need to think about three areas:

  • Terraform code — what we want our Infrastructure to look like.
  • Terraform state — the last known state of our infrastructure.
  • Infrastructure state — the actual state of our infrastructure (real time).

Terraform holds state (in a state file) so that it knows the current status of infrastructure. When you request changes to infrastructure Terraform will compare what you want (your code) with what you currently have (your state).

The important thing to remember here about State is that it is not a reflection of the actual state of your infrastructure. Terraform works out the current state of your infrastructure by calling different API’s behind the scene. This is important and it bears repeating. Terraform state is not a direct reflection of the actual state of your infrastructure. 

By now you might be wondering… but what does all of this have to do with refactoring infrastructure? Don’t worry, we’re getting to the different features of Terraform and how they facilitate refactoring very soon! But we need to understand that refactoring Terraform means carefully balancing across these three areas: our code, terraform state, and the infrastructure state.

But before we move onto the main features of Terraform that help us refactor, let’s cover two important concepts for Terraform: planning and applying.

Terraform Plan

When you come to make a change to your Terraform code, you’ll likely be using two important commands: Terraform Plan, and Terraform Apply.

A plan is where you ask Terraform to compare the current state with the requested state. And Terraform will respond with some details. Terraform will tell you if anything has changed, what’s changed and what the impact of rolling the change out will be. For instance, some changes will require that entire infrastructure is destroyed and rebuilt.

An example of a Terraform Plan command

Terraform Apply

We use Terraform plan to make sure our code would result in the changes we want. And when we’re happy with our changes, we use Terraform apply to make the changes.

And that’s it for our introduction to Terraform, we can now get to the really fun part, which is understanding how Terraform features enable us to easily refactor our Infrastructure!

Let’s jump into an example to see these two Terraform commands in action.

3 Terraform features to help refactor infrastructure

Okay, hopefully by now you should have a good grasp on how Terraform works. Now let’s get into the good stuff and look at some more advanced features and how they enable us to write infrastructure-as-code that’s flexible and manageable so that we can make changes without breaking a sweat!

Sound good? Let’s get to it!

Turning infrastructure into code: With Terraform import.

As we said before state is the way that Terraform knows the infrastructure we’re managing. But sometimes, for whatever reason we have infrastructure that wasn’t written in Terraform and we wish it was, so that we can make changes with all the benefits of infrastructure-as-code.

And Terraform gives us a tool to bring existing infrastructure under our own control. Through an import command. With Terraform import you simply provide Terraform with the unique identifier of a cloud resource (and provided that it’s supported by Terraform!) Terraform can grab that state and pull it down for you. Unfortunately though Terraform doesn’t yet support the importing of code, just the importing of state.

Now that you’ve pulled down your state, you have a process similiar to TDD where you can write your infrastructure-as-code to now match your state. You do this by writing bits of code and running the Terraform plan command to check if Terraform still tells you that your code and your state are out of line. With a little bit of fiddling you can bring infrastructure that was manually created and write it as code, and pretty easily too!

But again, what does this have to do with refactoring? Well, when you can import a resource under Terraform you can use Terraform to make future changes. When your infrastructure is managed in code it becomes easy to make copy environments for testing, and we can easily roll forward or back if we make a mistake.

The description of the Terraform import command. 

Monolithic to manageable infrastructure-as-code: With remote state

We talked before about the idea of state, which is Terraform’s way of knowing what infrastructure currently exists that it should be managing. Well up until now i didn’t share any details on how we can store state.

The simplest way you can store state, is locally. What do I mean? Well, when Terraform runs and makes changes to its state, it is stored in a basic Terraform state file and can be committed with your code. But… this leads to many complications. What if many people are working on the same state? And what if the state contains sensitive information?

And that’s where a neat Terraform feature comes in: remote state. We can use some simple configuration in our Terraform that let’s Terraform know that we want to store state remotely. When working in AWS, for instance that means it pushes your JSON file up to AWS and stores your state there.

But again, why is remote state useful for refactoring? One of the big advantages of remote state is that we can share state between state files. Using a data importer in Terraform we can pull in remote state created by different Terraform code.

But — so what?

By being able to pull in other Terraform’s remote state we can reference infrastructure built in different infrastructure files. Which makes it easy to break down our infrastructure into small bits, keep it simply documented and well described. Just as we might want to break down a large application code base we can keep Terraform well maintained by using remote state.

Multi-Account AWS Terraform Setup with Encrypted Remote State on S3 Backend

Source: restcomm

Managing all things cloud: With Terraform HCL

It’s now becoming common that when creating applications that software engineers piece together many different cloud services, such as Auth0 or Stripe. If you’re interested Ryan Hoover, the creator of Product Hunt wrote a pretty neat article about the idea of “No Code” apps (A product I created — Splitoo — falls into this “No Code” category, too).

But again, what does this have to do with infrastructure-as-code and Terraform?

Because with Terraform you can actually write infrastructure code for all these types of cloud applications, not just your regular cloud providers like AWS, GCP, etc.

Which is why we talked about the idea as Terraform as stand-alone. Because Terraform isn’t tied to a cloud platform it means that your Terraform knowledge can be transferred no matter what type of infrastructure you’re converting into code, it’s not only servers and databases etc. And it’s actually possible to write these more niche resources as infrastructure-as-code.

Having a tool that’s separate from these providers means that it’s easier to move between them. Want to integrate a GCP service when the rest of your infrastructure is in AWS? Well it’s easier now that you’re familiar with Terraform as a tool  and creating new resources in different places becomes significantly easier.

Image result for terraform providers

Example of Terraform Providers

It’s your turn — Terraform everything!

Hopefully I’ve piqued your interest about Terraform and some of the key advantages. I’ve really enjoyed working with Terraform in the last few weeks. I’ve found (because of the features we are talking about) that Terraform is very much a superior tool.

If you touch any infrastructure, I’d strongly, strongly advise that you take the time to learn how to put it into infrastructure-as-code first. And if you’re going to learn any tool to manage your provisioning of infrastructure-as-code I’d seriously recommend Terraform.

And that’s all for today, three features that Terraform gives us that makes it flexible and easy to refactor our infrastructure. As always, the best way to learn is to have a go. If you’re thinking about having a go creating cloud resources with something like AWS do remember to setup your AWS account properly so you don’t get hacked!