A primer on scaling and automating with Terraform.
Before I started using the cloud to deploy apps, I used to deploy them on bare metal infrastructure. Even though we could utilize scripts to automate some tasks, the majority of the work had to be done by hand. These attitudes remained unchanged when I began running apps in the cloud. I used to do all of my configurations by hand.
I had read about Terraform but hadn’t really given it much thought until I started to notice how much repetition I was doing and how some tasks could be automated.
It is possible to relocate your applications to the cloud and still discover no value if you continue to operate in your old ways.
What is Terraform?
Terraform is simply a file named main.tf that contains scripts written in HCL format. You define the resources you require inside the file and Terraform takes care of the rest. Terraform is supported by all the major cloud providers.
Why you should use Terraform
Given that most of my projects are small, I find it difficult to sit down and build an entire script simply to setup one GCE instance and possibly a load balancer.
However, as time goes on, I continue to make improvements to my infrastructure, thus years later I am unable to provide a snapshot of my resources, which occasionally results in cost and time overruns.
Using Terraform, I can run a single command and see all of the resources in my project; additionally, when I need to replicate the environment from staging to production, I am guaranteed of the exact same result, which aids in budget management, time savings, and avoiding shipping software with bugs.
Working in a team would be inconceivable without the adoption of an automated tool. Terraform allows you to set up a shared state that has a locking mechanism, which makes teamwork synchronous.
How Terraform works
For simple deployments, just create a “main.tf” file, specify your resources, and then run terraform apply. you can get sample files from terramform.io
Here is a sample script that will spin a GCE instance, setup a static IP, configure networks & create a cloud bucket
terraform {
required_providers {
google = {
source = "hashicorp/google"
}
}
}
provider "google" {
version = "3.5.0"
project = "<YOUR PROJECT ID>"
region = "us-central1"
zone = "us-central1-c"
}
resource "google_compute_network" "vpc_network" {
name = "terraform-network"
}
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "f1-micro"
tags = ["web", "dev"]
boot_disk {
initialize_params {
image = "cos-cloud/cos-stable"
}
}
network_interface {
network = google_compute_network.vpc_network.self_link
access_config {
nat_ip = google_compute_address.vm_static_ip.address
}
}
}
resource "google_compute_address" "vm_static_ip" {
name = "terraform-static-ip"
}
# New resource for the storage bucket our application will use.
resource "google_storage_bucket" "example_bucket" {
name = "examplemanythings"
location = "US"
website {
main_page_suffix = "index.html"
not_found_page = "404.html"
}
}
# Create a new instance that uses the bucket
resource "google_compute_instance" "another_instance" {
# Tells Terraform that this VM instance must be created only after the
# storage bucket has been created.
depends_on = [google_storage_bucket.example_bucket]
name = "terraform-instance-2"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "cos-cloud/cos-stable"
}
}
network_interface {
network = google_compute_network.vpc_network.self_link
access_config {
}
}
}
terraform apply
Terraform Modules
In many ways, Terraform modules are similar to the concepts of libraries, packages, or modules found in most programming languages, and they provide many of the same benefits
Use local modules to organize and encapsulate your code. Even if you aren’t using or publishing remote modules, organizing your configuration in terms of modules from the beginning will significantly reduce the burden of maintaining and updating your configuration as your infrastructure grows in complexity.
Terraform State
The primary purpose of Terraform state is to store bindings between objects in a remote system and resource instances declared in your configuration. When Terraform creates a remote object in response to a change of configuration, it will record the identity of that remote object against a particular resource instance and then potentially update or delete that object in response to future configuration changes.
In the default configuration, Terraform stores the state in a file in the current working directory where Terraform was run. This works when you are getting started, but when Terraform is used in a team, it is important for everyone to be working with the same state so that operations will be applied to the same remote objects.
Working with backends
Each Terraform configuration has an associated backend that defines how operations are executed and where persistent data such as the Terraform state is stored.
The persistent data stored in the backend belongs to a workspace. Initially the backend has only one workspace, called default, and thus only one Terraform state is associated with that configuration.
By default, Terraform uses the “local” backend, which is the normal behavior of Terraform you’re used to.
Here are some of the benefits of backends:
- Working in a team: Backends can store their state remotely and protect that state with locks to prevent corruption. Some backends, such as Terraform Cloud, even automatically store a history of all state revisions.
- Keeping sensitive information off disk: State is retrieved from backends on demand and only stored in memory.
- Remote operations: For larger infrastructures or certain changes,
terraform applycan take a long time. Some backends support remote operations, which enable the operation to execute remotely. You can then turn off your computer, and your operation will still complete. Combined with remote state storage and locking (described above), this also helps in team environments.
You can add this script to the one above to make it stateful
terraform {
backend "gcs" {
bucket = "<Your Bucket Name>"
prefix = "terraform/state"
}
}
terraform init
terraform apply
Conclusion
Use Terraform
Thank you for taking the time to read this post; we hope you found it useful; please provide feedback using the WhatApp button below.