Learning notes on Terraform and Terragrunt

Terraform/Terragrunt is a powerful tool to provision cloud resources. This post is to talk about some key feature and few tricks about it. Firstly, to describe them in quote,

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.

Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules

Both of them are powerful tools and I am supposed to do this post long time ago. Now finally motivated enough to pull together a few bits and pieces I have learned along the way by using terraform in practice. Here is the list.

  1. Remote State & Locking

    This can’t be emphasized enough. Remote state enables trackable resource management and alleviate teamwork conflicts. And most importantly, this feature has been extended by terragrunt so that we can do inherited structure of config setting, which means Don’t-Repeat-Yourself. Take below for example,

    This remote_config setting will support all other backends types by terraform as well.

    And when this file is included when running terragrunt, all belowing terraform settings will be updated.

     

  2. Modularity is king of re-usable code

    This is my favourite feature of terraform. Creating modules means the code can break into multiple levels of granularity. And each level of complexity VS repentance can be easily managed at no cost (except for calling init again for redeclaring the modules before calling plan). A simple setup would looks like below,

    (Note: the double slash (//) is intentional and required. It’s part of Terraform’s Git syntax for module sources. Terraform may display a “Terraform initialized in an empty directory” warning, but you can safely ignore it.)

    This is only the starting point. Some further thinking may be,

    1. Different modules could have different dependencies. Since terraform doesn’t support module level dependency. It could be done by terragrunt.

       
    2. Modules managed by terragrunt requires a lot of tfvars file. Maybe for simpler project managing one module in terraform which gathers all the pieces for other modules will be easier, which essentially is creating one master module on top of other modules. It gives better experience when transfering this project to pure terraform. And it much clearer in the way that tfvars files are defined.
  3. Loop, if-else syntax with magic “count”
    Essentially its terraform Interpolation of variables. Terraform can support both list and map types. Below are some most inspiring examples I have known so far.

    However, there is a BIG catch when using the count. DON’T DEPENDS COMPUTED RESOURCES. Since count is sent before dynamically computing any resources. So at the stage count is calculated, computed resource/numbers won’t be availabe. So you will get below error,

     

  4. Connecting gap between terraform & terragrunt
    1. Including Sequence

      Child block when including will always override the parent block settings if the setting has the same name. However, if the setting has a different name, the two sets will be merged together. And if in this case, the child setting takes higher priority. Two useful functions to mention here,

      find_in_parent_folder() : This function returns the path to the first terraform.tfvars file it finds in the parent folder above current terraform.tfvars file.

      path_relative_to_include() : This function returns the relative path between the current terraform.tfvars file and the path specified in its include block. It is typically used in root terraform.tfvars file so each child module store its state file at different key.

    2. Readable Global VARs

      Some environment variable is visible to both terragrunt and terraform. For example export TERRAGRUNT_IAM_ROLE="arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" is equivalent to call terragrant with option --terragrunt-iam-role "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME". Further example could be,

      TF_VAR_name

      TF_CLI_ARGS

      TF_INPUT

In summary, using terraform is so much a better experience compared to other alternatives. No never-ending JSON template file and dodgy (at least IMO) DSL syntax.

Here for FYI useful links,

https://github.com/gruntwork-io/terragrunt

https://www.terraform.io/docs/providers/aws/index.html

https://www.terraform.io/docs/configuration/interpolation.html

https://blog.gruntwork.io/terraform-tips-tricks-loops-if-statements-and-gotchas-f739bbae55f9