The promise of Terragrunt is to make it easier to maintain Terraform code by providing a wrapper around modules, adhering to "Don't repeat yourself" (DRY) configuration as well as better remote state management. For a complete explanation of features, take a look at the excellent documentation.
The Terraform code contained in aws
is split into several independent modules that all use their own remote Terraform state file. These modules know nothing about Terragrunt and are used by Terragrunt as simple infrastructure definitions. All the Terraform code in aws
is environment agnostic, this means, it does not know if it runs in dev
, staging
, or production
. This is achieved through variable interpolations. For example a Kubernetes cluster in staging
requires less powerful compute nodes than in production
. As a result the Kubernetes worker definition contains the var.primary_worker_instance_types
variable.
The directory structure inside aws
reflects the split into independent modules. For example, common
, contains all the networking logic required inside the application, while eks
and rds
represent the deployments of the Kubernetes cluster and the RDS database. The advantage is that if changes need to be made to infrastructure, should they fail, the state file has less chance of corruption and blast radius is decreased. Additionally, there are significant time gains in running modules independently as the infrastructure dependency graph is limited.
Terragrunt scripts are found in env
, which defines all the environment specific variables. Contained are subdirectories that define all the Terraform modules that should exist in each environment.
Running terragrunt plan
locally (as opposed to through the GitHub actions) can speed up development, in particular to see if your new terraform code is horribly broken. You will need two things:
notify-staging
aws profile set up.terraform.tfvars
file, preferable not in a git repo.Now:
/env/staging/eks
(note: in /env/staging
, not /aws
)AWS_PROFILE=notify-staging terragrunt init
AWS_PROFILE=notify-staging terragrunt plan --var-file ~/TEMP/terraform.tfvars
Important notes:
terragrunt apply
from your laptopChanges are applied through Git merges to this repository. Terragrunt supports the idea of remote Terraform configurations based on tags. This mean we can setup the following continuous integration workflows:
terraform plan
on all modules against staging
and report changes if there are anymain
branch that touch code in aws
and env/staging
run a terraform apply
against staging
and update the staging environment. The merge to main
also tags the commit based on semantic versioning.terraform plan
on all modules against production
and report changes if there are anytag
used to deploy to productioninfrastructure_version.txt
to perform plan
and apply
, respectively, to productionenv/production
and runs terraform apply
to apply changes to production
⚠️ We had to perform some actions on other repositories or manually using the AWS Console. Here is a list of these actions:
aws_ses_domain_identity
et aws_ses_domain_dkim
)Within the Makefile, you can pull the Target Group ARNs using the get-tg-arns
command
# If you would like to specify an environment, it can by done like so
AWS_PROFILE=notify-staging make get-tg-arns
aws/cloudfront
Assets to create to serve static assets on CloudFront CDN.
aws/common
Common networking assets such as:
aws/dns
DNS specific outputs for the domain nameserver
aws/eks
Assets to create a working Elastic Kubernetes Service (EKS):
aws/elasticache
Assets an Elasticache Redis cluster.
aws/lambda-api
Assets to create and hook up a lambda function for the api: the lambda function, an api gateway, and the private container repository (currently required for deploying images into lambda functions).
To add or change environment variables we
PRODUCTION_NEW_VARIABLE
and STAGING_NEW_VARIABLE
variables.tf
file. Be sure to mark any sensitive variables with sensitive = true
. This should prevent them from being revealed in the terrafrom plan.lambda.tf
by adding a line such as NEW_VARIABLE = var.new_variable
aws/rds
Assets to create a working Relational Database Service (RDS) using Aurora PostgreSQL.