Reflections on IaC using Terraform
Terraform has emerged as one of the top open source infrastructure as code (IaC) tools, since its initial release by Hashicorp back in 2014.
The design philosophy behind the tool is to have declarative, and stateful representation for the underlying IT infrastructure (whether it be on public, on-premise, or hybrid cloud), which in turns simplify the control, collaboration, and auditing of the cloud resources.
The classical example to show the main idea creating a VM:
provider "aws" { }
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
}
resource "aws_instance" "this" {
ami = "ami-026b57f3c383c2eec"
instance_type = "t2.micro"
tags = {
Name = "New example instance"
}
}
This is not limited to only compute resources, many of AWS services are available as well.
Simplified Workflow
The main workflow is conventionally as follows:
The flow maps cleanly to CLI commands:
terraform init
terraform plan
terraform apply
terraform show
Additional linting commands available as well:
terraform fmt
terraform validate
Disposal of resources is simplified as well (without authoring .tf
manifests):
terraform destroy
Structure
It is recommended to factorize input values across environments into variable
blocks.
This enhances for security posture as well, like protecting sensitive data.
Moreover, output
blocks provide a way to capture and log information after applying state changes.
The minimal structure of managed resources in terraform is shown below:
$ tree
├── main.tf
├── outputs.tf
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf
The variables and output files are separated to organize things up.
The state is tracked in .tfstate
file, and managed internally by Terraform.
Providers
The mechanism behind provisioning the intended state of an infrastructure or platform, is performed on by “providers”. They are terraform extensions written in Go
language exposing the resource types they implement, and interfacing with the target infrastructure / platform APIs.
provider "aws" {
region = "us-east-1"
}
The major providers are available on the public terraform registry, along with many platform agnostic plugins, such as Helm
and Kubernetes
.
Here’s an example for a simple helm releasing technique:
provider "helm" {
kubernetes { }
}
resource "helm_release" "redis" {
name = "redis-instance"
repository = "https://charts.bitnami.com/bitnami"
chart = "redis"
set {
name = "architecture"
value = "replication"
}
}
Terraform v.s. Ansible
Compared to Ansible as an orchestration tool on the infrastructure layer, I find that Terraform overall is more expressive and concise to enable building on modules in much elegant and feasible manner, with the excellent readability of HCL and dependency management of plugins.
The state is a major difference to consider here.
Ansible takes a stateless approach by always exchanging the desired state with the target resources in order to know the actual state then apply the delta, if needed. On the other hand, Terraform is stateful and manages the state in local or remote manner.
Summary
All in all, codifying infra and platform layers (e.g. using terraform) can bring key benefits to organizations in adopting the DevOps practices, leading to operational excellence, eventually.