Terragrunt - Directory Structure
Published: August 06, 2023 Last Updated: Author:
Terragrunt has created a features page where they have linked their documentation detailing how to maximize DRYness across various scenarios. I am going to create a directory structure that allows me to achieve as much DRYness as possible based on the recommendations from the official documentation.
it is not necessary that you follow the same structure. You can come up with your own.
The Terragrunt Directory Structure
My GitHub repository for Terragrunt has the following bare structure:
|-- modules
|-- single-account
|-- environments
|-- common.yaml
`-- terragrunt.hcl
The modules
directory will house any modules we develop. For now, we'll focus on basic scenarios involving multiple VPCs within a single AWS account, hence the single-account
directory. Within this, there's an environments
directory, where each sub-directory represents a specific environment we'll establish. Each of these environment-named directories will feature an environment.yaml
file, holding environment-specific configurations for Terragrunt to relay to Terraform.
Additionally, within the environments directory, we find a common.yaml
and a terragrunt.hcl
file.
The common.yaml
contains common configuration, as follows, what will be used across all environments:
aws:
region: us-east-1
state:
bucket_name: nixknight-terragrunt-demo-state
file_name: state.json
tags:
Managed-By: Terragrunt
The terragrunt.hcl
file holds the top-level Terragrunt configuration, which will be applied across all our environments. It reads both the existing common.yaml
. As we progress, this configuration will also accommodate any future environment.yaml
files we introduce.
locals {
vars = yamldecode(file("common.yaml"))
env_vars = yamldecode(file("${path_relative_to_include()}/../environment.yaml"))
environment_tags = local.env_vars.tags
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite"
contents = <<EOF
variable "aws_provider_default_tags" {
type = map
}
provider "aws" {
region = "${local.vars.aws.region}"
default_tags {
tags = var.aws_provider_default_tags
}
}
EOF
}
inputs = {
aws_provider_default_tags = merge(local.vars.tags, local.environment_tags)
}
locals
are a way to define a named value that can be used throughout the Terragrunt configuration. It's similar in concept to Terraform's own locals, where you can define reusable expressions so that you don't have to repeatedly write out the same values.
When Terragrunt runs a Terraform command, it first evaluates the generate
blocks and generates the specified files. In this case we are using it to generate a Terraform provider configuration.
According to Terragrunt documentation as of this writing, any inputs provided are set by Terragrunt as environment variables (TF_VAR_*) for Terraform. In our setup, we have specified a value for the aws_provider_default_tags
variable, aligning with what's declared in our provider configuration. Notably, Terragrunt will honor any pre-existing TF_VAR_*
environment variables set prior to its execution.
This directory structure is quite basic. We'll expand upon it as we progress.
Tagged as: Linux Terraform Terragrunt IaC AWS DRY