A design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design
.
βββ environment
βΒ Β βββ module.hcl
βΒ Β βββ dev
βΒ Β βΒ Β βββ inputs.hcl
βΒ Β βΒ Β βββ terragrunt.hcl
βΒ Β βββ preproduction
βΒ Β βΒ Β βββ inputs.hcl
βΒ Β βΒ Β βββ terragrunt.hcl
βΒ Β βββ production
βΒ Β Β Β βββ inputs.hcl
βΒ Β Β Β βββ organisation.tf
βΒ Β Β Β βββ terragrunt.hcl
βββ application
βΒ Β βββ app_1
βΒ Β β βββ module.hcl
| βΒ Β βββ dev
| βΒ Β βΒ Β βββ inputs.hcl
| βΒ Β βΒ Β βββ terragrunt.hcl
| β βββ preproduction
| βΒ Β βΒ Β βββ inputs.hcl
| βΒ Β βΒ Β βββ terragrunt.hcl
| β βββ production
| βΒ Β Β Β βββ inputs.hcl
| βΒ Β Β Β βββ terragrunt.hcl
βΒ Β βββ app_2
βΒ Β βββ app_3
βββ common.hcl
βββ _settings.hcl
You implemented the WYSIWYG pattern and have instantiated your module multiple times in your layers and are tired of copying them or/and made some mistakes while doing so.
The context pattern for WYSIWYG aims to keep your code DRY (Donβt repeat yourself)! π
Thus all concepts from the WYSIWYG pattern apply to this pattern.
Donβt repeat yourself is the motto of terragrunt. Terragrunt allows you:
Each terragrunt layer defines one and only one module, but input for this module can be defined throughout the tree structure. Example:
.
βββ environment
βΒ Β βββ module.hcl # Defines the module used by every subsequent layer
βΒ Β ββββ dev
βΒ Β Β Β βββ inputs.hcl # Defines **unique** input for this layer (Ex: the database should be a bit smaller in dev)
βΒ Β Β Β βββ terragrunt.hcl # Defines terragrunt configuration
βββ common.hcl # Defines default value to every layer (Ex: tenant id, size of the database)
βββ _settings.hcl # Defines required_version of terraform, terraform provider used but not the version and unique identifier for the backend **for every layer**
The context of a layer is all the inputs required for it to be created. Your tree structure, with inputs throughout it, is thus your context.
If your context is DRY, then your tree structure is OK. If you have to repeat an input you might want to refactor your tree structure. Check the refactoring section for details.
Each terragrunt layer defines one and only one module, you can not create a new resource independently without adding it to the module. This will force you to ask the question
Should this new resource really be added to this layer ? Isnβt this resource a new project need ?
Consequently, you can either:
The biggest advantage of terragrunt is that since every layer is a single module thus a single state. When identifying a new projectneed,d you can rearrange you tree structure to match the new view of your project need.
While terragrunt allows you to have a DRY configuration. It also allows you to easily split layer to match project needs This will enforce you to rethink your splitting every time you add a resource / module to a layer.
In Example 1 the use case is that we want to add resources for a new frontend. At this point you have 2 choices :
has_frontend
boolean variable is a temporary solution and should be used with caution, as It may hide a change in your projectβs needs.
βββ application
βΒ Β βββ module.hcl # Calls the backend module
βΒ Β ββββ app_1
| Β Β βββ dev
βΒ Β Β Β β βββ inputs.hcl
βΒ Β Β Β β βββ terragrunt.hcl
β βββ production
β Β Β Β Β βββ inputs.hcl
β Β Β Β Β βββ terragrunt.hcl
βββ _settings.hcl
My application needs a frontend, but only for this one app
.
βββ application
βΒ Β βββ backend
βΒ Β β βββ module.hcl
β βΒ Β ββββ app_1
β β βββ dev
β βΒ Β Β Β β βββ inputs.hcl
β βΒ Β Β Β β βββ terragrunt.hcl
β β βββ production
β β Β Β Β Β βββ inputs.hcl
β β Β Β Β Β βββ terragrunt.hcl
βΒ Β βββ frontend
βΒ Β βββ module.hcl
β Β Β ββββ app_1
β βββ dev
β Β Β Β Β β βββ inputs.hcl
β Β Β Β Β β βββ terragrunt.hcl
β βββ production
β Β Β Β Β βββ inputs.hcl
β Β Β Β Β βββ terragrunt.hcl
βββ _settings.hcl
.
βββ application
βΒ Β βββ module.hcl # Calls the backend module
βΒ Β ββββ app_1
| Β Β βββ dev
βΒ Β Β Β β βββ inputs.hcl
βΒ Β Β Β β βββ terragrunt.hcl
β βββ production
β Β Β Β Β βββ inputs.hcl
β Β Β Β Β βββ terragrunt.hcl
βββ _settings.hcl
Iβm going to need a Redis for my backend Iβll juste update my module backend and test it by overwriting the call to the module within the layer terragrunt.hcl
input.hcl
defines all the inputs spcefique to the layermodule.hcl
defines the module used by subsequent layersterragrunt.hcl
defines in every layer the terragrunt configuration of includecommon.hcl
defines default value to every layer_
are created with the generated functionThere are a lot of ways to organize your files and include function. Here is a proposition :
terragrunt.hcl
_settings.tf
file with backend configuration and Terraform provider and versioninput.hcl
that defines all inputs requiredterragrunt.hcl
describing includes with input.hcl
, the root terragrunt.hcl
and if needed the parent module.hcl
Pros:
Cons: