Author – Ajinkya R. Bhabal, Associate Cloud Engineer
Overview
First, start with a quick introduction to IaaC Tool and Services.
- Terraform – It is a tool for safely and efficiently building, combining, and launching any cloud, infrastructure, or service. It is available for most popular cloud platforms like Azure, AWS, Google cloud, and many more.
- Terragrunt – Terragrunt is a thin wrapper that provides extra tools for keeping your terraform configurations DRY, working with multiple Terraform modules, and managing remote state.
How terragrunt comes in a Terraform Structure?
The initial purpose of terragrunt was to fill in gaps of terraform features, by solving some of the key issues which were faced in the production environment. Terraform has been extensively working on adding a new features on daily basis, but still, there’s some space for improvement. Terragrunt has been providing rich features some of them are given below.
- Keep your provider configuration DRY
- Keep your Terraform CLI arguments DRY
- Keep your Remote configurations DRY
Before writing the terraform code for core features of terragrunt. Let’s setup an environment and understand some prerequisites for the terragrunt.
To use it,
- Install terraform
- Install terragrunt
- Put your Terragrunt configuration in a terragrunt.hcl file.
- Now, instead of running terraform directly, you run the same commands with terragrunt:
- Terragrunt plan
- Terragrunt apply
- Terragrunt output
- Terragrunt destroy
- We used Azure cli authentication to connect to the account.
- Make sure to have Azure blob storage container prior to deploying resources in the different resource group for remote backend.
Let’s discuss each feature one by one here, we will include all this configuration in terragrunt.hcl file.
1. Keep your provider configuration DRY
In terraform normally you have to copy paste this provider configuration in every one of your Terraform modules. So, if we want to Apply DRY principal here, then with the help of terragrunt this feature write the configuration once and use this in the parent as well as all child modules will achieve more efficiency. This isn’t a lot of lines of code but can be a pain to maintain. In the root terragrunt.hcl file, you would define the provider configuration using the generate block:
#Keep your provider configuration DRY
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
version = "=2.20.0"
features {}
}
EOF
}
2. Keep your Terraform CLI arguments DRY
CLI flags are another common source of copy/paste in the Terraform world. For example, a typical pattern with Terraform is to define vnet name variable in a variable.tf file:
# variable.tf file
variable "vnet_name" {
default = "test-vnet"
}
The arguments will be passed for variable in terraform command as given below.
$ Terraform apply -var=”vnet_name=stage-vnet”
So rather than writing an argument while running terraform command, we can specify in terragrunt configuration file.
# vnet_name.tfvars file
vnet_name = "prod-vnet1"
#Keep your Terraform CLI arguments DRY
terraform {
extra_arguments "common_vars" {
commands = ["plan", "apply"]
arguments = [
"-var-file=vnet_name.tfvars"
]
}
}
3. Keep your Remote configurations DRY
Terraform backends allow you to store Terraform state in a shared location that everyone on your team can access, such as a Blob container, and provide locking around your state files to protect against race conditions.
Normally in Terraform you have to copy/paste the same backend configuration into every one of your Terraform modules. Not only do you have to copy/paste, but you also have to very carefully not copy/paste the key value so that you don’t have two modules overwriting each other’s state files!
To Resolve this issue terragrunt come up with a great feature where you will write backend configuration once and use it multiple times.
#Keep your backend configuration DRY
remote_state {
backend = "azurerm"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
resource_group_name = "Ajinkya-RG1"
storage_account_name = "store1822"
container_name = "tfstate1"
key = "${path_relative_to_include()}/terraform.tfstate"
}
}
Now we will specify the main declarative resource configuration terraform file and variable declaration file.
# main.tf file
#Resources which will be created
# Create a resource group
resource "azurerm_resource_group" "example" {
name = "Ajinkya-RG2"
location = "East US"
}
resource "azurerm_virtual_network" "main" {
name = var.vnet_name
address_space = ["10.30.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dns_servers = ["10.0.1.4"]
}
resource "azurerm_subnet" "internal" {
name = "internal"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.30.2.0/24"]
}
# variable.tf file
variable "vnet_name" {
default = "test-vnet"
}
The following commands will deploy these resources in the azure.
$ terragrunt init
With the help of terragrunt init terraform will download all the required packages to deploy resources.
$ terragrunt plan
Now terragrunt plan command will run terraform plan command and will describe desired state configuration of the infrastructure.
$ terragrunt apply
With the help of terragrunt apply will deploy infrastructure into the Azure cloud.
Now we will take a look at Virtual network resource which we deployed in the Azure through IaaC.
With all the wonderful features Terragrunt brings to Terraform, we will have more efficiency while deploying infrastructure through IaaC Tool.