Contact Us
Python BlogDjango BlogBig DataSearch for Kubernetes AWS BlogCloud Services



Introduction to Infrastructure as Code with Terraform

October 13, 2020

Terraform, by HashiCorp, is a very useful tool in the arsenal of any seasoned DevOps or cloud infrastructure engineer. It is an Infrastructure as Code (IaC) tool, which can be used to define and manage resources from a variety of local and cloud service providers. It is useful for maintaining repeatable, understandable, and consistent infrastructure. 

Terraform accomplishes this by converting its declarative configuration files, which describe the desired shape and state of the infrastructure and application, into sets of API calls which it can execute to make that state a reality. It saves the results of those calls as "state," which it uses on subsequent runs to determine if changes are needed. Put simply, you tell it what sort of infrastructure and resources you want, and Terraform goes and sets them up for you.

Let's take a closer look at how to use Terraform, and how it converts code into infrastructure:

Command and Configure

To start using Terraform (after installing it and configuring it for your providers) you will write a configuration file. Terraform Configuration files have extension .tf  and are written using the HashiCorp Configuration Language syntax, which is “designed to be easy for humans to read and write” (it's also possible to use straight JSON).

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

resource "aws_instance" "example" {
  ami           = "ami-830c94e3"
  instance_type = "t2.micro"

This Terraform configuration specifies that there should be an AWS Instance in the region us-west-2 with an instance type t2.micro built using the AMIami-830c94e3. The credentials Terraform should use in issuing the API calls to verify and create this instance can be found using the [default] section of the current user’s ~/.aws/config. Alternatively, this could be configured to use environment variables, or assumed roles.

Before Terraform can spin this up for you, you must run terraform init which caches provider applications and module configs into .terraform. Terraform will complain if you don't run this command first. All Terraform commands should be executed in the directory which has the Terraform Configuration Files you wish to use.

Once that's taken care of, you can run terraform plan and Terraform will reach out to AWS (or your chosen remote provider), figure out what you already have running there and compare it with what you want. It will then inform you of what changes it needs to make. If you detect any errors at this point, simply change your config files and run terraform plan again. If you're ready to go run terraform apply.

terraform apply will first give you the same preview as plan did and then asks if you want to go ahead and apply these changes. Respond yes and Terraform will execute the plan.

A note on best practices:

While it might be tempting to skip the step of running plan, since you get the same information from apply with an option to cancel the changes, it is strongly recommended to use plan consistently while making changes to the configuration files, and only run apply when you're relatively certain you're ready to pull the trigger. There is nothing quite like the headache of a mistakenly applied set of Terraform changes.

Once your resources are live, you can change your configuration file at any time, and run terraform plan to see changes and terraform apply to execute the desired changes. Terraform does not run on the background — like Salt, Puppet, or Chef — it runs only when invoked. Changes to your configuration file, and therefore your infrastructure, can and should be tracked using version control.

If you want to spin down all of your resources, you can run terraform destroy. This works like terraform apply, as it will tell you all the resources it plans to destroy and prompts you with yes or no.

The Terraform State File and Other Useful Commands

By default, Terraform keeps a state file locally called terraform.tfstate. Its primary function is to store bindings between the resources declared in your configuration and the resources configured in your providers (e.g. AWS, GCP, Datadog). It stores references to the remote objects, addresses, and other metadata. Basically, terraform.tfstate contains everything it will need to update that resource on a later date, as well as information about it that might be useful to the engineer. When teams are using Terraform,  it is typical to configure the state data to be written to a cloud storage service so that the latest information is always readily available.

You can probe the state file using terraform state:

Terraform refreshes the state information from resource Providers when you run Terraform operations, so it's always up to date before applying any Terraform config file.

$ terraform state show 'packet_device.worker'
# packet_device.worker:
resource "packet_device" "worker" {
    billing_cycle =  "hourly" 
    created       =  "2015-12-17T00:06:56Z" 
    facility      =  "ewr1" 
    hostname      =  "prod-xyz01" 
    id            =  "6015bg2b-b8c4-4925-aad2-f0671d5d3b13" 
    locked        = false

Output from an example terraform state show query.

Main Takeaways

This should give you a pretty good primer on what Terraform is and how to use it. For more information, do peruse their extensive documentation, as well as the getting started guides. Now that the basics are out of the way, we'll be expanding on this series with posts on more obscure features, tips, and tricks for Terraform. Keep an eye out for those.

Tell us about the goals you’re trying to accomplish.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.