gruntwork-io / terragrunt-infrastructure-live-example

A repo used to show examples file/folder structures you can use with Terragrunt and Terraform
https://www.gruntwork.io/
Apache License 2.0
784 stars 474 forks source link
examples terraform terragrunt

Maintained by Gruntwork.io

Example infrastructure-live for Terragrunt

This repo, along with the terragrunt-infrastructure-modules-example repo, show an example file/folder structure you can use with Terragrunt to keep your Terraform and OpenTofu code DRY. For background information, check out the Keep your code DRY section of the Terragrunt documentation.

This repo shows an example of how to use the modules from the terragrunt-infrastructure-modules-example repo to deploy an Auto Scaling Group (ASG) and a MySQL DB across three environments (qa, stage, prod) and two AWS accounts (non-prod, prod), all with minimal duplication of code. That's because there is just a single copy of the code, defined in the terragrunt-infrastructure-modules-example repo, and in this repo, we solely define terragrunt.hcl files that reference that code (at a specific version, too!) and fill in variables specific to each environment.

Be sure to read through the Terragrunt documentation on DRY Architectures to understand the features of Terragrunt used in this folder organization.

Note: This code is solely for demonstration purposes. This is not production-ready code, so use at your own risk. If you are interested in battle-tested, production-ready Terraform code, check out Gruntwork.

How do you deploy the infrastructure in this repo?

Pre-requisites

  1. Install OpenTofu version 1.6.0 or newer and Terragrunt version v0.52.0 or newer.
  2. Update the bucket parameter in the root terragrunt.hcl. We use S3 as a Terraform backend to store your state, and S3 bucket names must be globally unique. The name currently in the file is already taken, so you'll have to specify your own. Alternatives, you can set the environment variable TG_BUCKET_PREFIX to set a custom prefix.
  3. Update the account_name and aws_account_id parameters in non-prod/account.hcl and prod/account.hcl with the names and IDs of accounts you want to use for non production and production workloads, respectively.
  4. Configure your AWS credentials using one of the supported authentication mechanisms.

Deploying a single module

  1. cd into the module's folder (e.g. cd non-prod/us-east-1/qa/mysql).
  2. Note: if you're deploying the MySQL DB, you'll need to configure your DB password as an environment variable: export TF_VAR_master_password=(...).
  3. Run terragrunt plan to see the changes you're about to apply.
  4. If the plan looks good, run terragrunt apply.

Deploying all modules in a region

  1. cd into the region folder (e.g. cd non-prod/us-east-1).
  2. Configure the password for the MySQL DB as an environment variable: export TF_VAR_master_password=(...).
  3. Run terragrunt run-all plan to see all the changes you're about to apply.
  4. If the plan looks good, run terragrunt run-all apply.

Testing the infrastructure after it's deployed

After each module is finished deploying, it will write a bunch of outputs to the screen. For example, the ASG will output something like the following:

Outputs:

asg_name = tf-asg-00343cdb2415e9d5f20cda6620
asg_security_group_id = sg-d27df1a3
elb_dns_name = webserver-example-prod-1234567890.us-east-1.elb.amazonaws.com
elb_security_group_id = sg-fe62ee8f
url = http://webserver-example-prod-1234567890.us-east-1.elb.amazonaws.com:80

A minute or two after the deployment finishes, and the servers in the ASG have passed their health checks, you should be able to test the url output in your browser or with curl:

curl http://webserver-example-prod-1234567890.us-east-1.elb.amazonaws.com:80

Hello, World

Similarly, the MySQL module produces outputs that will look something like this:

Outputs:

arn = arn:aws:rds:us-east-1:1234567890:db:tofu-00d7a11c1e02cf617f80bbe301
db_name = mysql_prod
endpoint = tofu-1234567890.abcdefghijklmonp.us-east-1.rds.amazonaws.com:3306

You can use the endpoint and db_name outputs with any MySQL client:

mysql --host=tofu-1234567890.abcdefghijklmonp.us-east-1.rds.amazonaws.com:3306 --user=admin --password mysql_prod

How is the code in this repo organized?

The code in this repo uses the following folder hierarchy:

account
 └ _global
 └ region
    └ _global
    └ environment
       └ resource

Where:

Creating and using root (account) level variables

In the situation where you have multiple AWS accounts or regions, you often have to pass common variables down to each of your modules. Rather than copy/pasting the same variables into each terragrunt.hcl file, in every region, and in every environment, you can inherit them from the inputs defined in the root terragrunt.hcl file.