Introduction to the world of Terraform

Hemanthhari2000
13 min readApr 16, 2023

Understand the concept of Infrastructure-as-code (IaC) and it’s importance in managing cloud and on-prem resources.

Photo by C Dustin on Unsplash

Introduction

Managing resources, especially effective resource management, is a tough job to do when it comes to microservices applications. In a microservices architecture or application, it is very difficult to manage multiple virtual machines or servers, disk space, inbound and outbound rules, virtual private clouds (VPCs), and other computing resources all at once. Since services are divided into their own components or nodes, it is very difficult to maintain the resources or keep track of them manually. This leaves an open door to automating such manual tasks. This is where the tool Terraform comes into play.

Terraform is an open-source infrastructure-as-a-code (IaaC or IaC) tool built by HashiCorp that helps developers to create, manage, delete and version resources in both cloud and on-prem efficiently and safely. It is basically a tool where we can set up the infrastructure or destroy it completely with the help of few terraform commands. In this article we will be looking at how we can write terraform code and try to deploy our resources to AWS cloud.

Overview

Let’s look at some of the topics covered in this article.

  • What is Terraform?
  • Why do we need Terraform or any IaC tools?
  • Prerequisites
  • Implementation
  • Conclusion

What is Terraform?

Terraform is an open-source infrastructure-as-a-code software tool created by HashiCorp that lets users to set up an infrastructure using a simple, easy to understand, declarative configuration language known as HashiCorp Configuration Language (HCL), or optionally JSON. The idea behind IaC is that we write and execute the code to create, deploy, update and delete the infrastructure. Terraform tool lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features. It can also be used in a multi-cloud environment where one workflow is enough to manage other clouds.

Terraform leverages APIs (Application Programming Interfaces) in order to build and manage resources on cloud platforms and other services. Providers enable terraform to work with nearly any platform or service with an accessible API. There are multiple providers in terraform that manages different types of resources and services. There are providers like AWS (Amazon Web Services), Azure, GCP (Google Cloud Platform), Kubernetes, Oracle Cloud Infrastructure, GitHub and more, that are publicly available in the official Terraform Registry.

Terraform Flow (credit: HashiCorp)

The main steps involved in the terraform workflow consists of three basic stages.

  • Write: You determine resources that could span diverse cloud providers and services as a configuration files using HCL.
  • Plan: Based on the configuration files you write, Terraform creates an execution plan that defines the whole infrastructure that can be created, modified, or destroyed.
  • Apply: Once the plan is approved, Terraform will apply all the changes and provisions the specified infrastructure.

Why do we need Terraform or any IaC tools?

Terraform or any other IaC tools for that matter, makes it easy to configure, modify and delete resources in cloud. Managing cloud resources is tedious since, the process of creating or setting up an infrastructure manually is a repetitive task. We need some sort of an automated tool that can set up the whole infrastructure in matter of minutes with minimal efforts from the users side. IaC tools such as terraform are widely used since, most of the work when it comes to provisioning is automated with the help of some configuration files. IaC tools help reduce the manual work needed in setting up infrastructure and makes the process automated. It can also help in setting up multiple infrastructures as the configurations are written as code hence, they can be reused multiple times.

Terraform is one of the widely used IaC tools by many developers especially in DevOps. DevOps engineers leverage the concepts of terraform for setting up multiple resources in cloud in a declarative approach. Terraform was also built as a DevOps first, software solution, since most of the use cases of terraform is based on DevOps and cloud computing. There are a plethora of providers available in terraform registry that makes the tool easily pluggable. Terraform also takes an immutable approach to infrastructure, reducing the complexity of upgrading or modifying your services and infrastructure.

Top IaC Tools (credit: scand)

The biggest reasons why people prefer terraform is because of the following:

  • It supports multiple providers like AWS, Azure, GCP and more.
  • It is very flexible and also it can store local variables including passwords and cloud tokens on terraform registry in encrypted form.
  • It is portable as it mitigates the hassle of frequently switching providers.
  • It provides immutable infrastructure where configuration changes are done smoothly.
  • Terraform’s central registry allows users to collaborate with other teams and individuals on infrastructure.
  • Terraform basically does orchestration and not just configuration management.

Prerequisites

Let’s look at some prerequisites before we start implementing terraform and deploy an instance in AWS cloud.

  • Terraform
  • AWS CLI
  • AWS Account

Implementation

Let’s check if we have all the prerequisites to start with our application deployment using terraform. First, let’s check whether terraform is installed in the system. Go ahead and run the following command in your terminal.

terraform version

You should get something like this, if you have terraform installed.

Terraform v1.4.5
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v4.63.0

Terraform Installation

If terraform is not installed then please go ahead and install it using the following commands based on your OS. You can get more information regarding terraform installation here.

  • For Mac
brew install terraform
  • For Linux
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
choco install terraform

AWS CLI

If AWS CLI is not installed in your system then go ahead and follow the installation steps mentioned here.

Once the installation is done, type the following command in your terminal to verify whether aws cli is installed successfully or not.

aws help

AWS Account

Make sure you have an AWS account with a full IAM access account. If you do not have an AWS account please create a new account (preferably, free-tier account) before you proceed with this implementation. In this implementation I will be using AWS free-tier account.

NOTE: This implementation will create some resources and it is recommended to use AWS free-tier account. If your account is not free-tier then you are responsible for any charges that may apply in AWS.

We also need AWS Access Key and AWS Secret Access Key. If you don’t have these or you are not sure where to check for these credentials then please follow this guide to get your credentials.

Once you have the access keys then run the following command in your terminal and paste your AWS Access Key and AWS Secret Access Key values when prompted

aws configure

Prepare your application to deploy

As previously said, we will be deploying an existing application to the AWS cloud using terraform. I will be using a website called Tooplate.com which provides free HTML templates which we can use. For this example, I will be using a template called Tween Agency.

You can use this link to download any tooplate template https://www.tooplate.com/zip-templates/<TEMPLATE_UNIQUE_NAME>.zip . The TEMPLATE_UNIQUE_NAME can be found from the template homepage URL https://www.tooplate.com/view/2128-tween-agency. Here, 2128-tween-agency is the TEMPLATE_UNIQUE_NAME

Let’s create our user data script that will run during the instance creation time. So, we will be using apache2 to host our application locally in the instance. Create a file called user-data.sh and add in the following contents

#!/bin/bash
sudo apt update
sudo apt install apache2 wget unzip -y
wget https://www.tooplate.com/zip-templates/2128_tween_agency.zip
unzip 2128_tween_agency.zip
sudo cp -r 2128_tween_agency/* /var/www/html/
sudo systemctl restart apache2

We are just installing apache2 server and also downloading the template or application and storing it in /var/www/html/ path when the instance is created for the first time. I have used a template from tooplate website to demonstrate how deployment happens in the AWS cloud using terraform. Feel free to use which ever application you want to deploy to the cloud.

Finally, phew…. We are now ready to write some terraform configuration files.

Terraform configuration

In a new directory or folder, create the following files, namely, main.tf, provider.tf, variable.tf.

mkdir terraform-deploy-application && cd terraform-deploy-application
touch main.tf provider.tf variable.tf

Let’s add AWS as our provider in provider.tf file.

provider "aws" {
region = "us-east-1"
}

Once, the provider is set then we can go ahead and initialise terraform to work with the following configuration files.

terraform init

Now, we can define our variables in variable.tf file.

variable "aws_ami_id" {
type = string
default = "ami-0aa2b7722dc1b5612"
}

variable "aws_instance_type" {
type = string
default = "t2.micro"
}

variable "my_ip" {
type = string
description = "My Public IP Address"
default = "<YOUR_PUBLIC_IP_ADDRESS>/32"
}

Since, terraform uses HCL, we will be defining our variables like this. The ami id is the id of Ubuntu instance and we will be using t2.micro as our instance type. Lastly, make sure that you add in your public IP Address in you variable.tf file. We will be accepting traffic only from our IP and not from the internet.

Let’s configure our instance in main.tf file

resource "aws_instance" "web" {
ami = var.aws_ami_id
instance_type = var.aws_instance_type
user_data = file("user-data.sh")
vpc_security_group_ids = [aws_security_group.tween_sg.id]
key_name = "tween_key"
tags = {
Name = "tween-agency-web"
}
}

Here, we are configuring an instance and setting some properties such as security group, key pair and user data. We get the ami id and instance type from the variable file that we already specified. To use the variables from the variable file, we need to use it like this var.<VARIABLE_NAME>. AWS Instance need a security group that specifies some rules to our incoming and outgoing traffic.

Let’s look at configuring security groups.

resource "aws_security_group" "tween_sg" {
ingress = [
{
cidr_blocks = ["${var.my_ip}"]
description = "SSH from my IP only"
from_port = 22
to_port = 22
protocol = "tcp"
ipv6_cidr_blocks = []
prefix_list_ids = []
security_groups = []
self = false

}, {
cidr_blocks = ["${var.my_ip}"]
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
ipv6_cidr_blocks = []
prefix_list_ids = []
security_groups = []
self = false
}, {
cidr_blocks = ["${var.my_ip}"]
description = "HTTPS"
from_port = 443
to_port = 443
protocol = "tcp"
ipv6_cidr_blocks = []
prefix_list_ids = []
security_groups = []
self = false
}
]
egress = [
{
cidr_blocks = ["0.0.0.0/0", ]
description = ""
from_port = 0
to_port = 0
protocol = "-1"
ipv6_cidr_blocks = []
prefix_list_ids = []
security_groups = []
self = false
}
]
}

You can see that we add 3 rules for ingress which means incoming traffic and they are for SSH, HTTP and HTTPS. The value for cidr_blocks in ingress is a variable that is defined in variable.tf file. For egress the configuration is set to public since, our application is not communicating with any service or external server. If your application communicates with another service or server then make sure to change your egress configuration based on the application needs.

Finally, let’s look at our key pair and some output configuration so that we can ssh to our instances and display public dns of created instance on the terminal respectively.

resource "aws_key_pair" "tween_key_pair" {
key_name = "tween_key"
public_key = "<YOUR_PUBLIC_KEY>"
}

output "Info_From_AWS" {
value = format("%s%s", "ssh -i tween_key_pair ubuntu@", aws_instance.web.public_dns)
}

output "AWS_Instance_URL" {
value = format("%s%s", "URL: http://", aws_instance.web.public_dns)
}

In the above snippet, make sure to create your public and private keys and add the public key in the public_key field. If you want to create a public and private key please use the following command to generate a public and private key.

ssh-keygen -t rsa -b 2048

Copy the public key and paste it in the public_key field specified in the above snippet. We will be using private key during login into the instance.

At last, your main.tf file should look something like this.

That’s it, yes that’s it, we are done with our terraform configuration. It’s that simple. Note that we are not creating a new VPC here. We will be using the default VPC provided by AWS.

Now, let’s apply the terraform files, but first let’s format the terraform configuration files. Type the following command in the terminal

terraform fmt

Once, the files are formatted we can start to plan the infrastructure using the following command.

terraform plan

You should see all the necessary resources that will be added, modified or deleted and at the end you should see a short summary about the current changes. Here, we are going to add 3 resources to AWS cloud.

....
....
}
Plan: 3 to add, 0 to change, 0 to destroy.

The operation is indicated by using the following symbols

  • + sign : Resources to be created
  • ~ sign : Resource to be modified
  • - sign : Resource to be deleted

During the plan phase, terraform compares the changes with present terraform state file and based on the operation type the changes will be applied. Once, the changes are applied, then it automatically updates the terraform state from the new state. Let’s now apply the changes.

terraform apply

This command will connect to your provider, in this case AWS and create the resources in the backend. You should see something like this in your terminal. All the changes are applied and at the end you can see the instance URL and ssh command to connect to your instance.

Changes to Outputs:
+ AWS_Instance_URL = (known after apply)
+ Info_From_AWS = (known after apply)
aws_key_pair.tween_key_pair: Creating...
aws_security_group.tween_sg: Creating...
aws_key_pair.tween_key_pair: Creation complete after 2s [id=tween_key]
aws_security_group.tween_sg: Creation complete after 5s [id=sg-094eb7446d68b5751]
aws_instance.web: Creating...
aws_instance.web: Still creating... [10s elapsed]
aws_instance.web: Still creating... [20s elapsed]
aws_instance.web: Still creating... [30s elapsed]
aws_instance.web: Creation complete after 36s [id=i-0ef3a312d2e2c3549]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

AWS_Instance_URL = "URL: http://ec2-44-203-194-152.compute-1.amazonaws.com"
Info_From_AWS = "ssh -i tween_key_pair ubuntu@ec2-44-203-194-152.compute-1.amazonaws.com"

Once the resources are created you can login to your AWS dashboard to see the resources that are being created.

Instance created in AWS

Similarly, from the terminal we can copy the URL and paste it in the browser, you should see the application being deployed successfully.

Application deployed successfully

You can even ssh to your instance based on the command you see under output in the terminal. Make sure that you change the private key file permission using this command chmod 400 PRIVATE_KEY_FILENAME and then use the following command ssh -i <PRIVATE_KEY_FILENAME> ubuntu@xxx–xx–xxx–xx–xxx.compute-1.amazonaws.com to connect to the instance.

Status of apache2 in the instance is running

Yaay… We have successfully deployed our application to AWS cloud. That’s how easy it is to deploy our resources to cloud. By using terraform you would have seen that we have a lot of control over the resources that we create. All we have to do is just configure the required resources in terraform file and then terraform will take care of creating the resources needed.

If you want to delete or terminate created resources in the cloud, just type the following command

terraform destroy

This command will destroy or terminate all the resources created in the cloud. While destroying the infrastructure, we are prompted about the changes. After we approve it the infrastructure will be destroyed.

....
....
}
Plan: 0 to add, 0 to change, 3 to destroy.

Changes to Outputs:
- AWS_Instance_URL = "URL: http://ec2-44-203-194-152.compute-1.amazonaws.com" -> null
- Info_From_AWS = "ssh -i tween_key_pair ubuntu@ec2-44-203-194-152.compute-1.amazonaws.com" -> null

Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_key_pair.tween_key_pair: Destroying... [id=tween_key]
aws_instance.web: Destroying... [id=i-0ef3a312d2e2c3549]
aws_key_pair.tween_key_pair: Destruction complete after 2s
aws_instance.web: Still destroying... [id=i-0ef3a312d2e2c3549, 10s elapsed]
aws_instance.web: Still destroying... [id=i-0ef3a312d2e2c3549, 20s elapsed]
aws_instance.web: Still destroying... [id=i-0ef3a312d2e2c3549, 30s elapsed]
aws_instance.web: Destruction complete after 32s
aws_security_group.tween_sg: Destroying... [id=sg-094eb7446d68b5751]
aws_security_group.tween_sg: Destruction complete after 2s

Destroy complete! Resources: 3 destroyed.

You can view the code for this demo in my github.

Conclusion

In this article, we have seen what is terraform, why do we use terraform and other types of IaC tools. We have also deployed an application to AWS cloud with all the necessary configurations. We have written configuration files for the instance, security group and key pair. Also we have seen how easy it is to destroy the whole infrastructure with just one line command. As you can see terraform is really flexible and it can be easily integrated into CI/CD pipelines and DevOps environment seamlessly. I hope this article was useful to you all. Will see you in my next article until then, as always code learn repeat …….

Follow for more…

--

--