Introduction to Terraform
Introduction to Terraform
Cloud Providers
In the past if you needed more resources, you had to order them, then go to a lengthy process to install and configure it.
The migration to cloud give developers way more flexibility than it was possible before, now you could have more resources with a few clicks instead of days/weeks.
Cloud Providers
Most of them allow you to create resources manually, but this causes issues such as:
- Misconfiguration
- Non-reproducible
- Hard to track used resources
- Hard to delete orphan resources
Introduction to Terraform
To solve this issues the concept of IaC (Infrastructure as code) was created. They allow you to write down your infrastructure desired state as code and it will be used to deploy real infrastructure.
This strategy allows you to create resources in a automated and predictable way reducing errors and keeping history of changes.
Terraform is an IaC tool created by Hashicorp.
Terraform Characteristics
-
Uses a language called HCL (Hashicorp Configuration Language) to declare IaC.
-
It is platform agnostic allowing you to deploy to most of big cloud providers and even to deploy to multiple cloud providers.
-
Tracks the state of each resource deployed and gets them to your desired state.
HCL Code Example
terraform {
required_providers {
vercel = {
source = "vercel/vercel"
version = "~> 0.3"
}
}
}
variable "vercel_api_token" {
description = "Vercel API TOKEN"
type = string
sensitive = true
}
provider "vercel" {
api_token = var.vercel_api_token
}
resource "vercel_project" "project" {
name = "todo-list"
framework = "sveltekit"
git_repository = {
type = "github"
repo = "rodrigosaint/future-proof"
}
root_directory = "frontend"
}
Terraform State
Terraform state is a mechanism that terraform uses to know what has been deployed and it is referred back when executing commands so it can know what to create, edit or delete.
It is a JSON dump containing all the metadata about your Terraform deployment as well as details about all the resources that it has deployed.
It is named terraform.tfstate
by default and stored in the same directory where your terraform code is, but for better integrity and availability it can also be stored remotely, by using the backend feature.
Terraform Workflow
There are 3 major steps in the terraform workflow:
-
Write - You write your terraform code.
-
Plan - You use the plan command to review the changes that will be applied to your infrastructure.
-
Apply - Deploying the changes you made, provisioning real infrastructure.
flowchart LR Write ----> Plan Plan --> Write Plan ----> Apply
Terraform Init
terraform init
initialises the working directory that contains your Terraform code. It follows this steps:
-
Downloads components - Download modules and plugins (eg. providers and modules)
-
Sets up backend - Sets up backend that will store Terraform state file (eg. s3, terraform cloud).
This is a command that should be executed when you start a terraform or when you add/update providers or modules.
The downloaded providers are binaries that execute API calls to vendors, those API calls are abstracted away by terraform.
Terraform Plan
terraform plan
reads the code, creates and shows a plan of the execution/deployment.
The plan allows the developer to review the action plan before executing anything.
Terraform Apply
terraform apply
deploys the instructions and statements in the code provisioning the infrastructure specified.
It updates the deployment state tracking file.
Terraform Destroy
terraform destroy
is about deprovisioning infrastructure. It looks at the recorded state file created during terraform apply and deprovisions all resources created by it.
This command should be used with caution as it is a non-reversible command. Take backups and be sure that you want to delete infrastructure.
Terraform Providers
Providers are terraform's way of abstracting integrations with API control layer of the infrastructure vendors.
They can only be written in Go lang and when you run terraform init
only its binary is downloaded.
Terraform finds and install providers when initialising working directory (terraform init), by default, looks for providers in Terraform providers registry/
Providers are plugins. They are released on a different pace from Terraform itself, and each provider has its own series of version numbers, so as a best practice providers should have a specific version.
Configuring providers
Configuring AWS provider:
# provider is a reserved keyword
# aws tells the name of the provider that will be fetched on public terraform registry
provider "aws" {
region = "us-east-1" # this allows you to pass configuration parameters
}
Configuring Google provider:
providers "google" {
credentials = file("credentials.json")
project = "my-project"
region = "us-west-1"
}
Resources
Declaring providers will give you access to define the resources associated to them. In the example bellow you are creating an EC2 instance:
resource "aws_instance" "web" {
ami = "ami-a1b2c3d4"
instance_type = "t2.micro"
}
You can access the output of this resource following the pattern [resource-type].[resource-alias].[resource_property]
Querying Resources
You can fetch information from other resources using the data keyword.
data "aws_instance" "my-vm" {
instance_id = "i1234567890" # What will be queried, this will vary depending on the resource type
}
The providers will have a set of queries for their resources, and it is possible to access the values using data.[resource-type].[resource-alias].[resource_property]
Terraform Variables
# variable is a reserved keyword
# then comes the name of the variable
variable "my-var" {
# all the properties are optional
description = "My test variable"
type = string
default = "Hello"
sensitive = true # hides the value from the output
}
To reference a variable use the following structure var.[variable-name]
Variables can be defined anywhere but as a best practice they should be stored on variables.tf
Variable Validation
variable "my-var" {
# all the properties are optional
description = "My test variable"
type = string
default = "Hello"
validation {
condition = length(var.my-var) > 4
error_message = "The string must be more than 4 characters"
}
}
Terraform Outputs
output "instance_ip" {
description = "VM's private IP"
sensitive = false
value = aws_instance.my-vm.private_ip # The only config parameter required
}
Output variable values are shown on the shell after running terraform apply
.
Terraform Modules
It is just another folder or collection of terraform code. It groups multiple resources that are used together making code more reusable.
Every terraform configuration has at least one module, called the root module, which consists of code files in your main working directory.
Terraform Modules
Modules can be referenced from:
Local files
module "name-of-the-module" {
source = "./modules/vpc" # mandatory
version = "0.0.5" # module version
region = var.region # input parameters
}
Public registry
module "name-of-the-module" {
source = "hashicorp/consul/aws" # mandatory
version = "0.0.5" # module version
region = var.region # input parameters
}
Private registry
module "name-of-the-module" {
source = "app.terraform.io/example-corp/k8s-cluster/azurerm" # mandatory
version = "0.0.5" # module version
region = var.region # input parameters
}
More content
I have all my notes regarding Terraform and Terraform Certification here - https://www.rodsantos.dev/learning/terraform-certification-terraform-associate-003/