DEV Community

Cover image for Advanced Terraform: Getting Started With Terragrunt
Kelvin Onuchukwu
Kelvin Onuchukwu

Posted on

Advanced Terraform: Getting Started With Terragrunt

What Is Terragrunt?

Terragrunt is an open source tool developed by GruntWork that helps to reduce code duplication accross your Terraform projects - effectively keeping your terraform code DRY.

DRY is a popular acronym which means Do not Repeat Yourself.

Terragrunt can be used to manage Terraform code across multiple enviornments, multiple AWS accounts, handling dependency management, custom actions and versioning.

Terragrunt simplifies the management of multiple environments by providing a clear separation between them.
Terragrunt hooks can be used to perform actions before or after Terraform commands.

Terragrunt can be integrated with your CI/CD pipelines for automated infrastructure deployment.

Terragrunt is able to integrate with external secret management tools like Hasicorp Vault or AWS Secrets Manager for managing sensitive data.

In fact, you can use Terragrunt commands in place of basic terrafrom comands.

  • terragrunt init
  • terragrunt plan
  • terragrunt apply
  • terragrunt output
  • terragrunt destroy

Terragrunt lets you specify the IAM role to use. You can do this by using the _--terragrunt-iam-role_ CLI argument or the TERRAGRUNT_IAM_ROLE environmental variable. Terragrunt will call the sts-assume-role API and then expose the credentials it receives as environmental variables when invoking terraform. This makes it possible to seamlessly deploy infrastructure across different environments without having to store AWS credentials in plaintext.

Installing Terragrunt

To install terragrunt, make sure you have alredy installed terraform beforehand.

  • Follow this link to install terraform.
  • Download the Terragrunt binary from the releases page.
  • Select the correct binary for your OS.
  • Copy the link and download on your terminal using the wget command. Example: wget https://github.com/gruntwork-io/terragrunt/releases/download/v0.54.19/terragrunt_linux_amd64
  • Rename the binary to terragrunt: mv terragrunt_linux_amd64 terragrunt
  • Make the file executable: chmod u+x terragrunt
  • Move the file to the /usr/local/bin directory: `sudo mv terragrunt /usr/local/bin/terragrunt'
  • To verify your installation, run: terragrunt --version.

A Case Study

Let us now present a scenario for managing infrastructure with Terragrunt.

The following is a sample terraform code for creating an EC2 instance using Terraform.

`
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}

required_version = ">= 1.2.0"
}

provider "aws" {
region = "us-west-2"
}

resource "aws_instance" "app_server" {
ami = "ami-830c94e3"
instance_type = "t2.micro"

tags = {
Name = "ExampleAppServerInstance"
}
}
`

The probelm is, how do you create this instance across several environments?

Ordinarily, you would want to duplicate the same code for each environment and then modify the parameters.
You might wish to specify different instance types for each environment. For example, you might want to use a t2.micro instance for development environment, a t3.medium for test environment and a t2.large for production.

The probelm is that this would be a very manual process -inefficient and leaves plenty room for error. Using Terragrunt, we can improve thiscode without having to copy and paste the code across several environments.

Also these environments might be spread out across diffrent AWS accounts and you'd also have to worry about managing the different AWS credentials and IAM roles required.
The terraform backend does not support variables or any type of expression whatsoever. So you would have to manually copy and edit the backend configuration code for each of the environments.

Working With Terragrunt

First we need to create seperate directories for each of the enviornments. In each of the directories, a terragrunt.hcl file will be created. This is the configuration file for each of the environments.

Your directory structure should look like this:

Image description

First, we have to define a terraform block and declare the source of our EC2 module.

`
terraform {
source = "tfr:///terraform-aws-modules/ec2-instance/aws?version=5.6.0"
}

`
Now let's define a provider.
`

generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
profile = "default"
region = "us-east-1"
}
EOF
}
`
Now we need to declare an inputs block. This is where most of the magic of terragrunt happens.

we can simply define one terraform code for all our environments and then use the inputs block to change values as reuired across all the environments.


inputs = {
ami = "ami-0005e0cfe09cc9050"
instance_type = "t2.micro"
tags = {
Name = "grunt-ec2"
}
}

What is happening here is that the instance type, ami and tags are values that are intended to differ based on the environment.

My terragrunt.hcl file now looks like this:

Image description

I have replicated this in my test directory with a few changes. The instance type is t2.medium, the tags have also been modified to reflect the environment.

The terragrunt.hcl file in my test environment looks like this:

Image description

The next stage is to execute terragrunt commands to read our configuration and invoke terraform with it.

  • Switch to the dev directory.
  • First, run terragrunt init.
  • Now run terragrunt plan to see proposed infrastructure changes. This is how mine looks:

Image description

  • Run terragrunt apply to actually create the instance.

Repeat the steps above for the test environment.

Final Thoughts

If you followed this tutorial until now, I'm sure you must have begun to see the importance of terragrunt and how it helps manage terraform code acoss different environemnts while keeping your terraform code DRY.

Top comments (5)

Collapse
 
salwad_basha profile image
Salwad Basha Shaik

That's a great tool for managing different kind of environments. Please write more on this.

Collapse
 
kelvinskell profile image
Kelvin Onuchukwu

Yeah.. Okay.. I'll go into a deep dive later on.

Stay tuned!

Collapse
 
ydarb profile image
Brady

Can you explain the difference between using terragrunt and using a terraform lookup() with environment names? They seem very similar to me

Collapse
 
gugalp profile image
Luiz Gustavo

Sorry, but unless I misunderstood something you can just use Terraform templates and input variables. I don't really see the point on using Terragrunt.

Collapse
 
adichiru profile image
Adi

The idea of copying code to create a new env is not smart at all and not what people do... You can differentiate between envs in the pipeline... code is code, does not care about envs