17
Terraform - Code Structure
The previous Terraform blog gave us a basic introduction to Terraform. We also discussed writing a simple Terraform code to create an AWS EC2 instance with minimal code.
Maintaining all codebases in a single main.tf
file is good for beginners. However, this approach will lead to maintainability issues as our underlying infrastructure grows. Moreover, in practical situations, you might also need to deal with multiple environments (e.g. DTAP - dev/test/acceptance/production).
Other deciding factors for code modularization are as follows-
- Project Complexity
- Count of Terraform Providers involved
- Count of Infra resources to be maintained by Terraform
- Cadence of Infrastructure changes - daily / weekly / monthly
- Deployment Strategy - CI/CD Pipeline, GitOps, etc.
It is recommended to logically split the source code as follows:
-
provider.tf
- contains provider configuration in root module -
main.tf
- call modules, locals, and data sources to create all resources -
variables.tf
- contains variable declarations used inmain.tf
-
outputs.tf
- contains outputs from the resources created inmain.tf
-
terraform.tfvars
- contains variable definitions to provide default variable values. Terraform will automatically load variables from those files.
Let us refer to the initial Terraform code and understand how we can logically break it down further.
As shown in the above image,
- Red block will be part of
provider.tf
- Green block will be part of
main.tf
As we treat Terraform as IaC, we should ensure there are no hardcodings. These must be configured in variables.tf
. The following block must be defined for every variable.
variable "aws_region" {
type = string
description = "AWS Region"
# default value is optional.
default = "us-east-1"
}
A default value can be configured (as shown above) for a variable. However, we can override this value while executing the code at runtime.
terraform apply -var aws_region="eu-west-1"
Also, Terraform can search the environment of its own process for environment variables named TF_VAR_
followed by the name of a declared variable. This can be useful when running Terraform in automation.
export TF_VAR_aws_region = eu-west-1
For bulk values, it is of convenience to specify their values in a variable definitions file (with a filename ending in either .tfvars
or .tfvars.json
)
Terraform also automatically loads a number of variable definitions files if they are present:
- Files named exactly
terraform.tfvars
orterraform.tfvars.json
. - Any files with names ending in
.auto.tfvars
or.auto.tfvars.json
.
This variable can then be used to replace the hardcodings.
region = var.aws_region
Our code post formatting will look as follows:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~>3.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
"Environment" = "dev"
"Owner" = "g33kzone"
}
}
}
variable "aws_region" {
type = string
description = "AWS Region"
}
variable "instance_type" {
type = string
description = "AWS EC2 Instance Type"
}
variable "aws_ec2_ami" {
type = string
description = "EC2 AMI for Amazon Linux 2"
}
resource "aws_instance" "web" {
instance_type = var.instance_type
ami = var.aws_ec2_ami
tags = {
"Name" = "aws-ec2-demo"
}
}
aws_region = "us-east-1"
instance_type = "t2.micro"
aws_ec2_ami = "ami-04d29b6f966df1537"
We are done with the coding. Let us execute this Terraform code with the following commands:
# open your shell in the same project folder
# download the terraform core components
# and initialize terraform in this directory
terraform init
# Validate changes to be made in AWS after the execution
terraform plan
# -auto-approve is used to skip manual approval prompt
terraform apply -auto-approve
Do not forget to delete the infrastructure created to avoid incurring any costs.
# running this command will destroy all the resources
terraform destroy -auto-approve
Github Repo - https://github.com/g33kzone/tf-aws-ec2.git
In future posts, I will delve into Terraform Modules.