Getting Started with Terragrunt: Simplifying Terraform for Large Projects


  
MontaF - Sept. 13, 2024

3
0

...

Terragrunt is a thin wrapper for Terraform, designed to make it easier to manage large-scale Terraform configurations. While Terraform is excellent for defining infrastructure as code, managing complex configurations across multiple environments (like dev, staging, and production) can get tricky. This is where Terragrunt comes in—it provides additional tooling to help manage Terraform code, enforce best practices, and handle challenges like DRY (Don’t Repeat Yourself), managing state, and promoting reuse of infrastructure modules.

In this guide, we’ll walk you through Terragrunt, its features, and how it simplifies the use of Terraform, especially in environments with multiple dependencies and configurations. We’ll also set up a simple project with Terragrunt, so you can see how it works in practice.


1. What is Terragrunt?


Terragrunt was created by Gruntwork as an extension to Terraform. Its goal is to:

  • DRY Terraform configurations: Avoid repetition by encouraging reusable modules.
  • Manage remote Terraform state: Automatically configure and manage the backend (like S3) for Terraform state.
  • Manage multi-environment deployments: Simplify handling of different environments (dev, prod, etc.) and keep configurations clean.
  • Keep infrastructure code organized: Help with keeping configurations modular and readable, even as projects grow in complexity.


While Terraform is good at defining infrastructure, it doesn’t natively solve some practical problems of managing infrastructure at scale, such as shared configurations or consistent state management. Terragrunt fills these gaps.


2. Installing Terragrunt


You’ll need Terraform installed first since Terragrunt is a wrapper around it. Once you’ve set up Terraform, follow these steps to install Terragrunt.


Installation Steps:

2.1 Install Terragrunt on macOS (via Homebrew):

brew install terragrunt


2.2 Install Terragrunt on Linux/Windows (using the binary):

wget https://github.com/gruntwork-io/terragrunt/releases/download/<VERSION>/terragrunt_linux_amd64
chmod +x terragrunt_linux_amd64
sudo mv terragrunt_linux_amd64 /usr/local/bin/terragrunt


2.3 Verify Installation:

terragrunt --version

This command should output the installed Terragrunt version.


3. Terragrunt vs Terraform: Why Use Terragrunt?


While Terraform is a powerful tool, there are some challenges that developers often face when using it to manage infrastructure across multiple environments.

Here’s how Terragrunt improves the experience:


3.1 Managing Remote State Automatically

In Terraform, you must manually configure the backend (e.g., an S3 bucket) to store the state for each module.

Terragrunt can automate this process and ensure that the remote state is stored in a consistent, secure location.


3.2 DRY Principle and Code Reuse

Terraform can become repetitive when managing multiple environments or modules.

With Terragrunt, you can avoid duplicating code by using the terraform {} block to reference a reusable module and add environment-specific configuration only once.


3.3 Handling Dependencies

In complex infrastructures, resources often have dependencies on each other.

For instance, a VPC might need to be created before the subnets or EC2 instances.

Terragrunt simplifies handling these dependencies using the dependency block.


4. Understanding the Basics of Terragrunt


4.1 Folder Structure with Terragrunt

Terragrunt works by organizing Terraform code into modules and leveraging directories to represent environments (like dev, staging, prod). A common structure looks like this:

infrastructure
├── terragrunt.hcl       # Root Terragrunt config
├── live
│  ├── dev
│  │  └── terragrunt.hcl
│  └── prod
│      └── terragrunt.hcl
└── modules
   └── vpc
       └── main.tf      # Reusable Terraform code for VPC


4.2 The terragrunt.hcl File

This is where Terragrunt configurations live.

In a Terragrunt project, each environment has its own terragrunt.hcl file.

Here's a basic example of what a terragrunt.hcl file looks like:

terraform {
 source = "../modules/vpc"
}

inputs = {
 region = "us-west-2"
}


In this configuration:

  • source: Points to a Terraform module located in ../modules/vpc.
  • inputs: Provides input variables (like the AWS region) that are passed into the Terraform module.

Terragrunt uses this file to define configurations for each environment (dev, prod, etc.).


5. Managing Remote State with Terragrunt


One of the most powerful features of Terragrunt is its automatic state management.

With Terraform alone, you’d need to define the backend configuration for each module manually.

Terragrunt can do this automatically using the remote_state block.


Here’s how you would configure S3 as the backend for storing Terraform state:

remote_state {
 backend = "s3"

 config = {
   bucket = "my-terraform-state-bucket"
   key   = "${path_relative_to_include()}/terraform.tfstate"
   region = "us-west-2"
 }
}


  • ackend: Specifies the type of backend (in this case, S3).
  • bucket: The S3 bucket where the state is stored.
  • key: The path in the bucket where the state file is saved.
  • region: The AWS region where the S3 bucket is located.

Using this approach, you don’t need to repeat state configuration across multiple environments—it’s handled centrally by Terragrunt.


6. Setting Up Your First Terragrunt Project


Now that you know the basics, let’s walk through how to set up a simple Terragrunt project that manages AWS infrastructure (such as a VPC).


Step 1: Define the Module

First, we define the reusable Terraform code as a module. Let’s create a modules/vpc/main.tf file:

provider "aws" {
 region = var.region
}

resource "aws_vpc" "main" {
 cidr_block = var.cidr_block

 tags = {
   Name = "MainVPC"
 }
}

variable "region" {}
variable "cidr_block" {
 default = "10.0.0.0/16"
}


This Terraform code defines a VPC in AWS with a variable cidr_block. It can be reused for any environment.


Step 2: Configure Terragrunt for Each Environment

Now we’ll set up environment-specific configurations using Terragrunt. For each environment (dev, prod), create a terragrunt.hcl file.

live/dev/terragrunt.hcl:

terraform {
 source = "../../modules/vpc"
}

inputs = {
 region    = "us-west-2"
 cidr_block = "10.1.0.0/16"
}

remote_state {
 backend = "s3"
 config = {
   bucket = "my-terraform-state-bucket"
   key   = "dev/vpc/terraform.tfstate"
   region = "us-west-2"
 }
}


live/prod/terragrunt.hcl:

terraform {
 source = "../../modules/vpc"
}

inputs = {
 region    = "us-west-1"
 cidr_block = "10.2.0.0/16"
}

remote_state {
 backend = "s3"
 config = {
   bucket = "my-terraform-state-bucket"
   key   = "prod/vpc/terraform.tfstate"
   region = "us-west-2"
 }
}


Now, Terragrunt will automatically:

  • Use the vpc module for each environment.
  • Configure the correct cidr_block and region for each environment.
  • Store the Terraform state in the correct S3 path.


Step 3: Initialize and Apply

To deploy the VPC in the dev environment, navigate to the live/dev directory and run:

terragrunt init
terragrunt apply


This will initialize and apply the configuration in the dev environment.


For the prod environment, navigate to live/prod and repeat:

terragrunt init
terragrunt apply


Terragrunt manages all the backend state and infrastructure provisioning automatically for each environment.


7. Handling Dependencies in Terragrunt


Terragrunt makes it easy to define dependencies between resources.

For example, if you need to create subnets that depend on the VPC, you can use the dependency block to ensure the VPC is created first.


Here’s how you can define a dependency on the VPC in the subnets configuration:

dependency "vpc" {
 config_path = "../vpc"

 outputs = ["vpc_id"]
}

terraform {
 source = "../../modules/subnets"
}

inputs = {
 vpc_id = dependency.vpc.outputs.vpc_id
}


In this case, the subnets module depends on the vpc module, and Terragrunt will ensure that the VPC is created before provisioning the subnets.


Conclusion


Terragrunt is a powerful tool for managing Terraform configurations at scale.

By promoting DRY code, automating remote state management, and simplifying multi-environment setups, Terragrunt significantly enhances the Terraform experience.


In this guide, we covered:

  • What Terragrunt is and why it’s useful.
  • Installing and setting up Terragrunt.
  • Managing Terraform state with Terragrunt.
  • Organizing infrastructure using reusable modules.
  • Handling dependencies between modules.


By using Terragrunt, you can simplify the management of your Terraform infrastructure, especially in projects with multiple environments and dependencies.

Whether you’re working on AWS, GCP, or another cloud provider, Terragrunt can help you streamline your operations.


Happy coding!


Comments ( 0 )
Login to add comments