- Published on
Introduction to Infrastructure as Code with Terraform
6 min read
- Authors
- Name
- Karan Pratap Singh
- @karan_6864
Table of Contents
In this article we will be learning about Infrastructure as Code, approaches, benefits and then we'll learn basics of Terraform by understanding some of its fundamentals and useful commands.
We will also create a basic Terraform project and provision some resources!
What is Infrastructure as Code?
Infrastructure as Code (IaC) can be defined as managing and provisioning of infrastructure through code instead of through manual processes like provisioning resources through AWS, GCP console etc.
Approaches
There are two approaches Infrastructure as Code (IaC):
- Imperative
With this approach, we define our desired configuration as a sequence of commands executed in a certain order.
For example, using a bash script using AWS CLI to provision our resources.
- Declarative
A declarative approach defines the system's desired state, including what resources you need and any properties they should have.
For example, AWS Cloudformation, Terraform, Ansible, etc.
Benefits
Here are some benefits of using Infrastructure as Code (IaC):
- Consistency
The goal of IaC is to eliminate manual processes which helps us iterate faster while maintaining consistency as our infrastructure evolves
- Simplicity
IaC allows us to spin up an entire infrastructure architecture by running few scripts. We can pretty much provision not only for development but also for staging, production environments which makes our software development life cycle (SDLC) much simpler.
- Increased efficiency
IaC shifts power back into the developer's hand. As provisioning becomes more reliable and automated, engineers spend less time performing manual work, and more time executing higher-value tasks.
- Risk minimization
Imagine having a DevOps engineer who's the only one who knows your infrastructure setup and its ins and outs. Now imagine that engineer is leaving your company.
Here, IaC is a perfect fit because as a new engineer is onboarded, they won't need to spend much time understanding how our infrastructure is provisioned.
What is Terraform?
Terraform is an infrastructure as code (IaC) tool that allows us to build, change, and version infrastructure safely and efficiently.
Terraform uses HashiCorp Language (HCL) as its language to define a resource regardless of the provider being used.
Fundamentals
Let's look at some fundamentals and building blocks of a basic terraform project.
State
Terraform must store state about our infrastructure and configuration. This state is used by Terraform to map our resources to our configuration and keep track of metadata.
Terraform also provides tons of options for how we want to store our state. For example, if we are working with multiple people in the team we can store our state to something like AWS S3 or Consul rather than storing it locally
Provider
Providers are basically plugins that terraform uses to interact with cloud providers like AWS, GCP, Azure, etc. Terraform has tons of providers for pretty much any infrastructure needs and can be found at terraform registry
Example:
# AWS
provider "aws" {
region = "us-east-1"
}
# Google Cloud
provider "google" {
project = "example"
region = "us-west1"
}
Resource
Resource blocks can describe any infrastructure object such as compute, network or any higher-level component
Example:
resource "aws_apprunner_service" "some_name" {
tags = {
Name = "example-apprunner-service"
}
}
Data Sources
While Resource is used to manage a new infrastructure component. Data sources gives us a read-only view into pre-existing resources in our infrastructure that might or might not have been provisioned by Terraform itself.
Example:
data "aws_ebs_volume" "ebs_volume" {
most_recent = true
filter {
name = "volume-type"
values = ["gp2"]
}
}
Modules
Terraform modules are containers for multiple resources that are used together.
Imagine you want to provision an EKS cluster but as we know it's not as simple as defining an eks resource, we'll also need a vpc, subnets and the list goes on.
So modules become a nice way to organize your infrastructure, for example, we can just define our eks specific resources in eks module!
Example:
module "eks" {
vpc = "..."
instances = 10
}
But wait, there's more!
There are tons of modules and resources present on Terraform registry so we can probably find a module that fits our needs. Such as ready to use EKS module
You can also publish your own module to Terraform registry!
Functions
Terraform comes with tons of functions from String functions like join
, format
to FileSystem functions.
Variables
Variables can serve as input for resources, data sources, modules, functions, etc., and help us organize common config in a better way.
Example:
variable "bucket_name" {
type = string
default = "example-value"
}
Or a temporary local variable
Example:
locals {
random = "hello"
}
Output
Output in Terraform helps us define outputs we expect when our terraform script runs.
Example:
output "service_endpoint" {
value = aws_apprunner_service.service.domain_name
}
Commands
Here are some important terraform commands we'll be using:
Init Prepare and initialize our project
Plan Shows changes that'd be done by the configuration change
Apply Applies our changes
Destroy Destroys all the resources in our configuration
Installation
Terraform
Terraform cli can be installed from here
Note: HashiCorp also provides terraform docker image, if you don't like installing extra dependencies
AWS Access
We'll also need programmatic access and AWS CLI configured with our AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
.
You can refer to my earlier article, where I cover AWS CLI installation in detail
Hands on!
Enough theory, now let's actually use what we learned and provision something. To keep things simple, we'll be provisioning a S3 bucket on AWS
I'll create a terraform
directory with a main.tf
file.
$ mkdir terraform
$ touch main.tf
Let's define our AWS provider with our preferred region
provider "aws" {
region = "us-east-1"
}
Create a variable for our bucket name.
Note: make sure the bucket name is unique
variable "bucket_name" {
type = string
default = "sample-bucket"
}
Define our aws_s3_bucket
resource
resource "aws_s3_bucket" "deploy_bucket" {
bucket = var.bucket_name
acl = "private"
}
Add some output
output "s3_bucket_arn" {
value = aws_s3_bucket.s3_bucket.arn
}
Let's initialize our project
Great, our project has been initialized. Let's plan our changes
$ terraform plan
Everything seems good, Let's apply
$ terraform apply
Finally, let's cleanup our resources
$ terraform destroy
Conclusion
In this article we covered Infrastructure as Code, it's approaches, benefits along with Terraform. I hope this was helpful and as always feel free to reach out on twitter if you face any issues!