
Sam Gabrail
President at TeKanAid
Terragrunt is a thin wrapper for Terraform that provides extra tools for keeping your Terraform configurations DRY (Don't Repeat Yourself). With Terragrunt, you can easily manage remote states and multiple environments. It also helps you keep your codebase clean and organized.
Let’s take a look at our setup.
TL;DR: You can find the repo here.
There are several reasons to use Terragrunt over just using pure Terraform code. Below is a list of these and we will elaborate more under the Terragrunt Features section.
To install Terragrunt, download the binary for your operating system from the Releases Page and add it to your PATH. Alternatively, you could use a package manager as shown here. If you're following along with us with codespaces, you will have all the binaries already installed for you.
Instead of running Terraform commands directly, you run the same commands with Terragrunt:
These commands will call the corresponding Terraform commands, with Terragrunt performing additional logic before and after the Terraform calls.
Terragrunt can be used to manage your infrastructure configurations, plans, and Terraform backend. You can define your Terragrunt configuration in a terragrunt.hcl file, which allows you to reference specific versions of your Terraform modules and fill in variables specific to each environment. We will see an example later.
Let's now elaborate more on the key features that Terragrunt offers:
To make the most of Terragrunt, follow these best practices:
While Terragrunt offers many benefits, it also has some drawbacks, such as:
However, if you are using env0, you can make full use of Terragrunt's benefits because env0 is one of the few tools that support Terragrunt.
Yevgeniy Brikman, who is the co-founder of Gruntworks (the company that brought us Terragrunt), makes a great comparison between using Terraform workspaces, Git branches, and Terragrunt. He summed up his comparison with the table below:
Terragrunt can be used in various scenarios, such as managing infrastructure for different environments like development, staging, and production. In our example, we will see how to use Terragrunt to DRY out our Terraform configuration. We will first run everything with pure Terraform only then we will see how to improve our configuration using Terragrunt.
Furthermore, to keep things simple, we will only consider two environments: dev and prod.
We will use an example WordPress application to showcase the difference between using pure Terraform only and using Terragrunt. This example was taken from this repo, but modified slightly to fit our needs. The WordPress Terraform module creates the following resources:
You can check the Terraform code in our repo.
Below is the folder structure when using Terraform only.
Under each environment folder, you can see that we're duplicating code in both the main.tf and the outputs.tf files. Even though we are using a terraform module structure, we still duplicate the code unnecessarily. Recall that using terraform modules is a great way for code reuse.
Below is the content of the main.tf file for the dev environment.
Below is the content of the main.tf file for the prod environment.
There are two main factors to notice between the two main.tf files:
Now let's take a look at the output variables in the outputs.tf file for the dev environment:
Notice that they are exactly the same. So again this is violating the DRY principle and it becomes worse when you have many other environments and applications.
Follow the instructions below to deploy the WordPress application using pure Terraform code only.
In the Terraform_Only/environments/dev folder create a private/public key pair with an empty passphrase:
ssh-keygen -f mykey-pair
sudo chmod 400 mykey-pair
In order to create a remote backend to store Terraform state files, you will need to create an S3 bucket and a Dynamo DB table in AWS. This is a good guide.
Run Terraform commands
To deploy the production wordpress application, run the same steps above but in the Terraform_Only/environments/prod folder.
Here is the output of the terraform apply command:
And going to the URL http://54.167.129.51 shows you the WordPress setup screen:
Now let's take a look at how Terragrunt can improve our Terraform code structure.
Below is the folder and file structure in our local file system, when using Terragrunt. Notice that we have a root terragrunt.hcl configuration file and a terragrunt.hcl configuration file per environment folder.
Now let's take a look at the main or root Terragrunt configuration file called terragrunt.hcl just under the environments folder.
Notice how the key in the remote_state block is parameterized. Each environment folder will have its own key without us worrying about copying and pasting. So the dev environment's key will be: terragrunt/wordpress/dev/terraform.tfstate whereas the prod environment's key will be: terragrunt/wordpress/prod/terraform.tfstate
The second thing to notice is that we define the input variables that are common to all our environments here. Once again this shows how we are following the DRY principle.
Now let's take a look at the dev Terragrunt configuration files under both the environments/dev and the environments/prod folders.
Below is the terragrunt.hcl file under the environments/dev folder.
and below is the terragrunt.hcl under the environments/prod folder.
In both the dev and prod Terragrunt configuration files you can see that we're including the inputs from the root Terragrunt config file using the find_in_parent_folders() function.
We're also including the input variables that are specific to each environment. This is as DRY as it gets.
The second thing to notice is the source attribute inside the terraform block. Here we are referencing the terraform module wordpress that exists two levels above inside the modules folder. It's also possible to reference a terraform module that lives in a git repository, which is actually a more realistic pattern. In this case, another benefit of using Terragrunt is that you can source different versions of all the Terraform modules for different environments. For example, the dev environment may be running on version v0.0.2 of our wordpress module whereas the prod environment is still on version v0.0.1. Once the dev environment has been properly tested you can then upgrade the prod environment to version v0.0.2. With pure Terraform, you can't parameterize the source block rendering all environments running with the same version of the module unless you hard-code the version values.
Follow the instructions below to deploy the WordPress application using pure Terraform code only.
In the Terragrunt/environments/dev folder create a private/public key pair with an empty passphrase:
Then run the following Terragrunt commands:
Terragrunt sets the AWS remote backend for you. It will create an S3 bucket and a Dynamo DB table.
To deploy the production WordPress application, run the same steps above but in the Terragrunt/environments/prod folder.
Here is the output of the terragrunt apply command:
Notice the Terragrunt output is exactly the same as the previous Terraform only scenario except that we didn't need to define an outputs.tf file to output the variables from the module. Terragrunt did it for us for free.
And going to the URL shows you the same WordPress setup screen that we saw earlier.
The Terragrunt cache is a folder that Terragrunt creates in the current working directory to store the downloaded Terraform configurations, modules, providers, and backend settings. Terragrunt uses this cache to avoid downloading the same code multiple times and to speed up the execution of Terraform commands. You can safely delete this folder at any time and Terragrunt will recreate it as necessary. You can also change the location of this folder by setting the TERRAGRUNT_DOWNLOAD environment variable. Here is what it looks like
Terragrunt has a neat feature that allows you to run commands across multiple folders. In our case we will run the following command to destroy the dev and prod environments in parallel from within the Terragrunt/environments folder:
Below is the output showing both the dev and prod environments destroyed successfully.
As we've seen, Terragrunt offers several benefits over Terraform and helps to address some of the challenges inherent to Terraform implementations. Since Terragrunt is built on top of Terraform, it also benefits from env0 management.
When you use env0 in conjunction with Terragrunt, you get the following benefits:
Terragrunt is a powerful tool that enhances the Terraform experience by providing DRY code, versioning, dependency management, and hooks, among other features. By following best practices and leveraging Terragrunt's features, you can create a more efficient and maintainable infrastructure management process in large-scale deployments. Combine env0 with Terragrunt and you can unleash the full potential of your Infrastructure as Code strategy.
Use custom workflows to model any process
Visualize all IaC changes pre and post-deployment
Gain code-to-cloud visibility and governance
Improve developer experience and collaboration
Use custom workflows to model any process
Visualize all changes pre and post-deployment
Gain code-to-cloud visibility and governance
Improve developer experience and collaboration
env0 is the best way to deploy, scale, and manage your Terraform and other Infrastructure as Code tools.