An example on how to use Terragrunt in Azure
This repository contains a structured Terragrunt configuration for managing Azure infrastructure across multiple environments, regions, and deployment units.
In this example I use random resources to generate outputs so no azurerm is needed. This should be enough to test how Terragrunt can be used to handle configuration changes on different levels in the hierarchy.
The config to generate the backend config is in root.hcl and the subscription specific variables that needs to be set are in subscription.hcl.
.
├── _envcommon/ # Common configuration for deployment units
│ ├── unit1.hcl # Common configuration for unit1
│ └── unit2.hcl # Common configuration for unit2
├── common.variables.tf # Shared variables across all environments
├── root.hcl # Root-level configuration
├── dev/ # Development environment
│ ├── subscription.hcl # Dev subscription configuration
│ ├── euw/ # Europe West region
│ │ ├── site.hcl # Region-specific configuration
│ │ ├── dev1/ # Stack 1
│ │ └── dev2/ # Stack 2
│ └── use/ # US East region
├── prod/ # Production environment
└── ...
-
Install Terraform (version 1.0.0+)
-
Install Terragrunt
-
Install Azure CLI and authenticate:
az login
# Navigate to a specific unit directory
cd dev/euw/dev1/unit1
# Initialize and apply
export ARM_USE_AZUREAD=true
terragrunt init
terragrunt apply
# Navigate to a stack directory
cd dev/euw/dev1
# Apply all units in this stack
terragrunt run-all apply
Terragrunt allows overriding inputs at multiple levels in the configuration hierarchy. Here are several methods:
The simplest way to override inputs is through the command line:
terragrunt apply -var="resource_group_name=my-custom-rg"
The most powerful method leverages Terragrunt's hierarchical configuration:
Add or modify the inputs
block in a unit's terragrunt.hcl
:
# dev/euw/dev1/unit1/terragrunt.hcl
inputs = {
resource_group_name = "custom-rg-unit1"
}
# dev/euw/dev1/unit1/terragrunt.hcl
inputs = {
resource_group_name = "rg-${get_env("USER", "default")}-${local.environment}"
tags = merge(
local.common_tags,
{
Owner = get_env("TF_VAR_OWNER", "Team")
}
)
}
Terragrunt merges inputs from different levels with the following precedence (highest to lowest):
- Command line variables
- Environment variables
- Local
terragrunt.hcl
inputs - Parent directory inputs
- Common/default inputs
# dev/use/dev2/unit1/terragrunt.hcl
inputs = {
resource_group_name = "morgoth"
}
# _envcommon/unit1.hcl
inputs = {
resource_group_name = "celebrimbor"
}
- Keep overrides minimal and specific to each level
- Use common variables for shared settings
- Use descriptive variable names that indicate their scope
- Document custom overrides in comments
- Test overrides by running
terragrunt plan
before applying
For more information, refer to the official Terragrunt documentation.