Terragrunt: Simplify the management of your Terraform infrastructures (2023)

Originally Posted onblog de sokube


Setting up and managing the infrastructure for your cloud computing projects can be a tedious and time-consuming process.

An infrastructure solution like Code asTerraformarlets you create and manage cloud resources using configuration files.

As we'll see in this article, managing Terraform can be particularly complex when you need to manage multiple environments and minimize code reuse (DRY: don't repeat yourself!)Backends distintosfor each environment. Despite the use ofwork rooms, Terraform would only solve the first of these problems!

Lucky for usground gruntsolve these problems!

Introduction to Terragrunt

Let's take a look at the main benefits of Terragrunt.

Terragrunt: Simplify the management of your Terraform infrastructures (1)

File structure in Terragrunt

Terragrunt simplifies managing Terraform settings for multiple environments. Let's take a concrete exampleAzur.

We want to deploy an application that uses a lot of resources (app service,App Service Plan,resource group,safe key, etc.) as well asSQL databasefor persistent data:

(Video) How to use Terraform and Terragrunt with Infrastructure Code

Terragrunt: Simplify the management of your Terraform infrastructures (2)

We want to deploy this application to a development environment (developer), a scenic environment (staging) and a production environment (puncture).

Let's code 2 Terraform modules in advance:

  • Application: for app and resource group
  • Data base: for the database part

As an example, we could have this kind of file structure in Terraform, where each Terraform file is duplicated per environment, while Terragrunt's code is easier to understand and considered DRY:

Terragrunt: Simplify the management of your Terraform infrastructures (3)

On the left side of the image we can see that the "classic" terraform code must be maintained for each environment. We have to copy the code three times for the app and db modules, which is not ideal for maintenance. Also, we need to maintain a "backend" block for each environment.

In contrast, with Terragrunt, we physically separate our Terraform code into a Terragrunt code folder that only contains environment-specific variables.

We can observe:

  • Asourceterragrunt.hcl file that allows us to manage global settings for all our environments and dynamically generate a backend.
  • An "environment_specific.hcl" file in each directory that contains specific settings for our environments and is independent of modules.we could have calledterragrunt.hclbut I renamed it for clarity.
  • A module-specific terragrunt.hcl file containing the module definition (Where is our module?) and the variables to be passed.

If we want to generate and apply our Terragrunt plan (terragrunt plan, terragrunt apply) it is necessary to go to the specific folder of our environment.

(Video) What is Terragrunt and how to use Terragrunt? | Terragrunt Tutorial

Terragrunt can read the hcl files in the parent directories to get the complete code before execution.

For example, if we want to apply changes after making changes to the terragrunt/dev/app/terragrunt.hcl file, we'll go to the terragrunt/dev/app directory to run the terragrunt plan and terragrunt apply commands.

As an additional note, you can also go to the terragrunt/dev directory and run the terragrunt run-all plan command. All plans are displayed one after the other.

Of course, we can also keep all Terraform code in a different repository, so that each directory has its own lifecycle.

backend administration

With Terragrunt, you can simplify Terraform backend management using a centralized configuration. In our case, we store the backend inTerraforming Clouds. We have the ability to create a backend for each environment (dev, staging, prod) by specifying a single block of Terragrunt code in the root terragrunt.hcl file:

# /home/lionel/demo-terragrunt/terragrunt/terragrunt.hcllocals { # Holen Sie sich den Projektnamen env_config = read_terragrunt_config(find_in_parent_folders("environment_specific.hcl")) environment_name= local.env_config.locals.environment_name terraform_token = get_envUD_.TF_CLOKENA " ) }# Generiere ein Backend (eines pro Projekt)generiere "backend" { route = "backend.tf" if_exists = "overwrite_terragrunt" content = <<EOFterraform { cloud { organization = "sokube-test" workspaces { name = "demo- $ {local.environment_name}" } }}EOF}

First, we can note the use of a "locals" block, which will contain two variables:

  • Environment name directly generated by reading the "environment_specific.hcl" file which contains the name of our environment. It is interesting to note that we will use theselook_in_parent_folders()since, as mentioned above, we will be running the terragrunt plan command in the terragrunt/<environment>/<app|db> folder.
  • terraform_token initialized by retrieving the TF_CLOUD_API_TOKEN environment variable to connect to Terraform Cloud to create the backend. We don't want this value in our code for obvious security reasons. Of course, we could have stored this backend locally or remotely on AWS, Azure or GCP.

We want to isolate the environments as much as possible, with this solution each environment has its own TFState!

(Video) Getting started with Terragrunt

Variable management with terragrunt.hcl files

As we saw earlier, we store the environment_name variable in the specific_environment.hcl file present in each dev, staging and prod subdirectory. This variable was used to generate the backend, but it can also be used in our naming convention for our resources.

Our file looks like this:

# /home/lionel/demo-terragrunt/terragrunt/dev/environment_specific.hcllocals { Environment_name = "dev"}

module management

Now let's focus on our archives terragrunt/dev/app/terragrunt.hclandterragrunt/dev/db/terragrunt.hcl

In these files we declare the path where the terraforming module is located:

# /home/lionel/demo-terragrunt/terragrunt/dev/app/terragrunt.hcl# Enthält root terragrunt.hclinclude "root" { ruta = find_in_parent_folders()}locals { # Erhalte den Names des Archivs des Archivs env_specific.hcl env_config = read_terragrunt_config(find_in_parent_folders("env_specific.hcl")) environment_name = local.env_config.locals.environment_name}# Terraform-Block zum Aufrufen des App-Modulsterraform { source = "../../../terraform//app/" }-- -- --------------------------------------------- --- -- ------------------------# /home/lionel/demo-terragrunt/terragrunt/dev/db/terragrunt.hcl# Inklusive raiz terragrunt. hclinclude " root" { ruta = find_in_parent_folders()}locals { # Abrufen des Archivnamens des Archivs env_specific.hcl env_config = read_terragrunt_config(find_in_parent_folders("env_specific.hcl")) environment_name = local.env_config.locals.environment_name}# Bloco de Terraform para llamar a db moduleterraform {fuente = "../../../terraform//db/"}

It is also possible to specify a Git repository as a source.

Environment specific variables

We just need to pass the necessary variables to our modules for them to be called. To do this, just use an input block. This is how our final files would look:

# /home/lionel/demo-terragrunt/terragrunt/dev/app/terragrunt.hcl# Include root terragrunt.hclininclude "root" { path = find_in_parent_folders()}locals { # Get environment names from env_specific.hcl file env_config = read_terragrunt_config ( find_in_parent_folders("env_specific.hcl")) environment_name = local.env_config.locals.environment_name}# Terraform block to call app module sterraform { source = "../../../terraform//app/"}# Valuesinputs = { # That is, it is used for resource names env_name = local.environment_name # Other inputs variables1 = "My first value" variables2 = "My second value" variables3 = "My third value" variables4 = "My fourth value". . } ---- --------------------------------------------- - - ---- ------------------------# /home/lionel/demo-terragrunt/terragrunt/dev/db/terragrunt.hcl# Add root terragrunt.hclinclude " root" { path = find_in_parent_folders()}locals { # Get environment name from file env_specific.hcl env_config = read_terragrunt_config(find_in_parent_folders("env_specific.hcl") ) environment name = local.env_config. locals.environment_name}# Terraform block to call db moduleterraform { source = "../../../terraform//db /" }# Value inputs = { # ie used for resource names env_name = local. environment_name # Other entries variables1 = "My first value" variables2 = "My second value" variables3 = "My third value" variables4 = "My fourth value" .. .}

apply changes

Once our code is ready, all we need to do is generate the Terragrunt plan and deploy the resources.

(Video) Terraform and Terragrunt - Part 1 | Terraform Resources | Terraform AWS Examples | Terraform

Here's how we could deploy the resources or apply changes after changing an input variable in the terragrunt/dev/db/terragrunt.hcl file:

# Alternate for the next directory: cd /home/lionel/demo-terragrunt/terragrunt/dev/db# Initialize terragruntterragrunt init# Generate Terragrunt planterragrunt plan -out myplan.tfplan# Apply planterragrunt apply myplan.tfplan

This approach allows us to really isolate environments as well as changes to a specific module.

The displayed map is identical in all respects to a map displayed via Terraform!


After this basic usage of Terragrunt, we saw together how this tool offers many benefits for effectively managing Terraform deployments, as well as minimizing code duplication.

Allows easy navigation and better understanding of the file system by configuring various settings in terragrunt.hcl files.

We could also generate separate backends for each environment to isolate them from each other. This would not be possible with Terraform workspaces.

But while Terragrunt can offer practical benefits, it can also have some downsides, especially since it requires a separate tool to install and an extra layer of abstraction for teams to learn.

(Video) Connecting Terraform to Terragrunt

Finally, it should be noted that Terragrunt does not natively support Terraform Cloud and Terraform Enterprise, although workarounds are available.

Terragrunt is still a very interesting solution, especially in contexts that span many environments. For simple deployment in 1 or 2 environments, Terraform alone may suffice.

Terragrunt: Simplify the management of your Terraform infrastructures (4)
Keep it dry, but keep it simple!


1. Infra Automation - Terragrunt Framework Discussion -1
(T&T Cloud Techies)
2. 8 Terraform Best Practices that will improve your TF workflow immediately
(TechWorld with Nana)
3. Terraform testing | Test Azure Terraform with terratest | Terratest | Terragrunt | Azure terratest
(Bee a Learner 🐝🌨️)
4. Terraform tools review - terragrunt (part 1)
(Anton Babenko)
5. Terraform — Terragrunt
6. Terragrunt (part 1)
(Anton Babenko)
Top Articles
Latest Posts
Article information

Author: Sen. Emmett Berge

Last Updated: 03/29/2023

Views: 5848

Rating: 5 / 5 (60 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Sen. Emmett Berge

Birthday: 1993-06-17

Address: 787 Elvis Divide, Port Brice, OH 24507-6802

Phone: +9779049645255

Job: Senior Healthcare Specialist

Hobby: Cycling, Model building, Kitesurfing, Origami, Lapidary, Dance, Basketball

Introduction: My name is Sen. Emmett Berge, I am a funny, vast, charming, courageous, enthusiastic, jolly, famous person who loves writing and wants to share my knowledge and understanding with you.