Definition
Terraform is an open source, cloud-agnostic coding tool for provisioning and configuring Infrastructure as Code (IaC). It’s currently the most popular IaC tool.
IaC is the practice of using code and machine-readable files to automate the provisioning, configuration, and management of IT infrastructure.
Overview
Terraform was created by HashiCorp. It lets users describe the desired state of their infrastructure by writing configurations in a declarative, human-readable syntax called HashiCorp Configuration Language (HCL). We can use Terraform to provision and configure cloud or on-premise infrastructures.
IaC evolved from more traditional configuration management tools. Some well-known examples of these tools are Chef, Puppet, and Ansible. Terraform’s declarative approach to IaC differs from earlier tools by describing the intended result and state of its target infrastructure rather than the actions needed to achieve that state.
Terraform is also designed to be similar to tooling like CloudFormation and focuses more specifically on higher-level abstractions and configuring resources at the datacenter level. It’s intended to complement third-party configuration management tools to provide a holistic management platform for our entire infrastructure.
Terraform also separates the planning and execution phases of our deployments. It provides a command suite that stages configuration changes and lets us consult and review adjustments and their dependent ordering. We can then limit the scope of our modifications to only those we approve and execute changes with a clear understanding of the results.
How Terraform Works
The Terraform workflow uses three commands in the CLI to declare the state of our configurations: plan, apply, and destroy.
Configuration files represent the sources of truth that declare the resources describing our infrastructure. They’re written in Terraform language, an implementation of the HCL syntax designed to be easy to read by humans.
The Terraform language can be expressed in two variants: a native syntax, with which we write our configuration, and a JSON variant, which lets us more easily programmatically generate portions of our configuration.
The Terraform language consists of two main syntactic elements: blocks and arguments.
- Blocks act as containers that represent resources or other objects. They’re created with a block type and a body that can contain nested blocks or arguments and can also be created with any number of labels to aid readability.
- Arguments are used to assign an expression to a name. These expressions can be literals, references, or a combination of other expressions.
Let’s take a quick look at a Terraform configuration adapted from code originally on StackOverflow. This configuration has three files and illustrates a simple deployment using plan and apply.
There are three main steps in a Terraform deployment, which we accomplish through the Terraform CLI.
Writing Configuration Files
The first of the three files in the configuration represents a generic, cloud-agnostic configuration that can be used to create a DNS CNAME record in Amazon Web Services (AWS) using its Route53 service, or in Google Cloud Platform (GCP):
variable "cloud_provider" { default = "aws" }
variable "domain_name_record" {}
variable "domain_name_zone" {}
variable "domain_name_target" {}
module "aws_dns_record" {
source = "../../aws/networking/dns/record"
count = "${var.cloud_provider} == "aws" ? 1 : 0"
domain_name_record = "${var.domain_name_record}"
domain_name_zone = "${var.domain_name_zone}"
domain_name_target = "${var.domain_name_target}"
}
module "gcp_dns_record" {
source = "../../gcp/networking/dns/record"
count = "${var.cloud_provider} == "gcp" ? 1 : 0"
domain_name_record = "${var.domain_name_record}"
domain_name_zone = "${var.domain_name_zone}"
domain_name_target = "${var.domain_name_target}"
}
The second and third files in the configuration create DNS records on the specific cloud platforms we listed. The generic configuration uses both specific configurations, but each is passed several CNAME records to create — either zero or one. The number passed across is determined by the cloud_provider variable, which acts as a switch in this case.
The second file configures our AWS Route53 DNS record.
variable "count" {}
variable "domain_name_record" {}
variable "domain_name_zone" {}
variable "domain_name_target" {}
data "aws_route53_zone" "selected" {
count = "${var.count}"
}
name = "${var.domain_name_zone}"
resource "aws_route53_record" "cname" {
count = "${var.count}"
zone_id = "${data.aws_route53_zone.selected.count}"
name = "${var.domain_name_record}.${data.aws_route53_zone.selected.name}"
type = "CNAME"
ttl = "30"
records = [${var.domain_name_target}]
}
The third file configures our GCP DNS record.
variable "count" {}
variable "domain_name_record" {}
variable "domain_name_zone" {}
variable "domain_name_target" {}
resource "gcp_dns_record_set" "www" {
count = "${var.count}"
name = "${var.domain_name_record}.${var.domain_name_zone}"
type = "CNAME"
ttl = 300
managed_zone = "${var.domain_name_zone}"
rrdatas = ["${var.domain_name_target}"]
}
We can apply simple logic to templates by using variables and operators. With some minor modifications, this generic configuration could be used to create a resilient multi-cloud configuration that protects an application against outages.
Planning and Reviewing Changes
Next, we use the plan command to review any changes in the state of our configuration files. In an existing configuration that’s been modified, this command shows the difference between the previous and new versions. In a new configuration, it simply outputs the contents of the files. It’ll look something like this:
Applying Changes
Finally, we use the apply command to approve the changes we’ve made and provision the infrastructure. Terraform then uses our configuration to determine which APIs to request and which parameters to send. This creates our infrastructure.
Terraform then either creates or updates the terraform.tfstate file. This is the central source of truth against which our infrastructure is compared whenever the plan command is used, or deviations are otherwise detected. The output looks something like this:
Examples of Terraform
Terraform is a flexible solution and presents an ideal tool for many use cases.
Some organizations may want to use a multi-cloud deployment to increase fault tolerance. Terraform is a vendor-agnostic tool. It integrates with many different cloud providers and allows us to use variables and modules to create a layer of abstraction to hide vendor-specific configurations. This is a significant advantage that Terraform has over some other IaC tools. It allows us to avoid vendor lock-in so that we can manage both our cloud infrastructures and edge infrastructures with the same IaC tool.
Similarly, abstracting the configuration with variables allows us to use Terraform to manage parallel environments. This is particularly useful for creating test environments that are either exact replicas or scaled-down versions of those in production.
Terraform can also be used to perform self-service. We can implement a front end that triggers one or more Terraform configurations on the back end to provision infrastructure for other members of staff. This takes some heavy lifting away from those individuals or teams, streamlining processes.
This self-service scenario complements policy compliance and management use cases. Because Terraform is used to provision infrastructure, it allows us to enforce the type or size of resources being used. This process is straightforward when combined with HashiCorp Sentinel.
We can also use Terraform to stage software demos, which often require the software to run on one or more different platforms. Terraform ensures that the infrastructure is set up identically to how it was during development and handily demonstrates the speed and ease of deployment to the target platform.
Similarly, Terraform can be used as a form of disaster recovery to recreate infrastructure that has been accidentally deleted or modified by a user.
Key Takeaways
- Infrastructure as Code (IaC) is the practice of using code and machine-readable files to provision and manage IT infrastructure.
- Terraform uses the Terraform language to declaratively provision the resources we describe in our configuration files.
- The Terraform language implements Hashicorp Configuration Language (HCL) syntax, and it structures code using blocks and arguments.
- We can use Terraform to implement cloud-agnostic DNS records by using simple logic to select between blocks declaring specific records for each platform.
- Terraform is a flexible solution appropriate for various potential infrastructure scenarios.
- StackPath offers a Terraform Plugin for managing edge infrastructure.