Why Terragrunt?
The biggest reason is DRY (Don’t Repeat Yourself). Using Terraform modules is a critical first step toward DRY but without Terragrunt even the code to instantiate a module and set up input variables, output variables, providers, and remote state can still create a lot of maintenance overhead.
Another powerful functionality – is that you can add hooks to run certain commands with the terraform apply, before, after, or on error.
Who is in charge and what’s the revenue model?
Terragrunt is an open-source project maintained by Gruntwork. They are in charge of its development and maintenance.
Gruntwork’s revenue model involves offering support, consulting, and services around their tools, including Terragrunt and other infrastructure-related offerings. They provide paid subscriptions for enterprise support, training, and helping companies with infrastructure-as-code (IaC) implementations, while the core tools remain open-source.
How do I keep it DRY?
In the module repo(s), expose anything you want to be able to set as a terraform variable.
Have another repo with all your environment settings. Let’s call this repo live, pass those input parameters.
The source of the terraform module and the inputs are the only things you need to set per environment.
terraform {
# Deploy version v0.0.3 in stage
source = "git::git@github.com:foo/modules.git//app?ref=v0.0.3"
}
inputs = {
instance_count = 3
instance_type = "t2.micro"
}
(Note: the double slash (//) in the source parameter is intentional and required. It’s part of OpenTofu/Terraform’s Git syntax for module sources. OpenTofu/Terraform may display a “OpenTofu/Terraform initialized in an empty directory” warning, but you can safely ignore it.)
Terragrunt Generate
Where possible the easiest way to customize your module by environment is by passing input parameters to variables. However, sometimes this is not an option if you are using a module that you do not control and in that case you can still use a Terragrunt generate block to add Terraform resources into the downloaded module.
DRY State Management
Without Terragrunt – copy and paste this everywhere but change the key on each one. Also you have a bootstrapping problem. How do you create the s3 bucket to store terraform state? Where is the state for that going to be stored.
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "frontend-app/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "my-lock-table"
}
}
With Terragrunt – define once in the top-level (root) of each environment and for each module automatically match the key to the filepath. And you won’t have a bootstrapping problem. Terragrunt by default will automatically create the state bucket with all the recommended security settings.
# in the root
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
assume_role {
role_arn = "arn:aws:iam::0123456789:role/terragrunt"
}
}
EOF
}
# in the module invocation
include "root" {
path = find_in_parent_folders()
}