Terragrunt - Embracing the Terraform Wrapper

Published: July 22, 2023 Last Updated: Author: Saad Ali

Back in December 2020, I was involved in a project with a customer who were using Azure Cloud for their services. They had previously encountered significant challenges with another team that managed their Azure infrastructure. The customer's web application didn't scale well, and their demands were often not met in a timely manner. Despite migrating from bare-metal to the Cloud, their experience was far from satisfactory, largely due to the inadequacies of the infrastructure management team.

However, that team had written Terraform code. And since the Terraform code was the property of our customer, we naturally gained access to it. At first, I thought it was just Terraform modules without any Terraform code referring to them. However, as I delved into the code, I discovered terragrunt.hcl files with unfamiliar code blocks that referenced the modules. Curious, I researched Terragrunt. The customer had given us a target to recreate the infrastructure using this code, which would serve as proof that we could manage the infrastructure effectively and assist them in resolving issues.

Although we didn't possess any expertise in Azure, we still managed to rebuild the infrastructure and successfully helped our customer resolve their issues using the provided code. Subsequently, we formulated a transition plan and migrated our customer to AWS, where we utilized CloudFormation at the time.

TLDR ; our customer is happy.

Fast-forward to 2023. I've been using Terraform consistently to manage different aspects of our infrastructure. While writing code, my team and I have consistently encountered instances where we end up repeating certain patterns. Although we've developed modules for various patterns, we still find ourselves repeatedly writing the same module blocks in Terraform code, leading to tedious and non-DRY (Don't Repeat Yourself) code.

Even while in my personal test environments, repeating provider and backend blocks in Terraform feels awkward. Coupled with copy-pasta of module blocks for all environments, it becomes so boring and gives me the impression that the code lacks true DRYness. Its just copy-pasta everywhere. Ideally, I should only have to write configuration that differs between environments and let the code handle the rest. With that said, I have come across examples where people effectively utilize a combination of workspaces, tfvars, and locals to achieve some form of DRYness.

Furthermore, as the infrastructure becomes more complex and more resources are added, Terraform starts taking longer to refresh resources. While it's expected that Terraform should refresh resources, for a large and intricate environment, implementing a minor change should not consume an excessive amount of time primarily spent on refreshing the Terraform state.

This led me to research and resolve these things and I consistently found myself returning to Terragrunt. The same tool we had used back in 2020.

During my free time this past week, I explored various Terragrunt code patterns used by people on the internet. At some point, it became complex as I hadn't tried any of the code patterns before. That's when I decided to build some AWS infrastructure examples using Terragrunt while documenting the process through blog posts and GitHub.

I will keep updating this blog post with links to Terragrunt-related blog posts.

  1. Terragrunt - Initial Setup
  2. Terragrunt - Directory Structure
  3. Terragrunt - Dealing with AWS Infrastructure State

Tagged as: Linux Terraform Terragrunt AWS DRY IaC Cloud Azure