Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DRY deployments with Terragrunt

DRY deployments with Terragrunt

Presented at the PHPSW meetup in Bristol, UK (June 2022)

Vítor Brandão

June 08, 2022
Tweet

More Decks by Vítor Brandão

Other Decks in Technology

Transcript

  1. Infrastructure as Code · Terraform is an open source "Infrastructure

    as Code" tool, created by HashiCorp. · The Terraform language (HCL) is declarative, describing an intended goal rather than the steps to reach that goal. · Terraform providers are plugins that implement resource types typically in a public cloud provider. · The infrastructure provisioned is considered immutable (avoids configuration dri ).
  2. Terraform modules Terraform modules are small, reusable Terraform configurations for

    multiple infrastructure resources that are used together. ❯ modules/ !"" networking !"" website-db #"" website-ecs ❯ modules/website-ecs/ !"" ecs.tf !"" load-balancer.tf !"" locals.tf !"" outputs.tf #"" variables.tf
  3. modules/website-ecs/ecs.tf resource "aws_ecs_task_definition" "my_website" { family = local.project_name network_mode =

    "awsvpc" requires_compatibilities = ["FARGATE"] memory = 1024 container_definitions = jsonencode([ { name = "my-wordpress-website" image = "123456789.dkr.ecr.eu-west-2.amazonaws.com/my-wordpress-website-fpm:latest" environment = [ { name = "WORDPRESS_DB_HOST", value = var.db_endpoint }, { name = "WORDPRESS_DB_NAME", value = var.db_name }, ... }
  4. Terraform "components" Think of a module as a PHP class

    declaration and a component as instantiating that class. ❯ live/prod !"" networking #"" website ❯ live/prod/website !"" backend.tf !"" datasource.tf !"" main.tf !"" outputs.tf !"" providers.tf #"" variables.tf
  5. live/production/website/main.tf module "database" { source = "./modules/website-db" vpc_id = data.terraform_remote_state.networking.outputs.vpc_id

    subnets_id = data.terraform_remote_state.networking.outputs.subnet_id db_name = "wordpress" db_username = "wordpress" } module "ecs" { source = "./modules/website-ecs" vpc_id = data.terraform_remote_state.networking.outputs.vpc_id subnets_id = data.terraform_remote_state.networking.outputs.subnet_id db_endpoint = module.database.db_endpoint db_name = module.database.db_name db_username = module.database.db_username }
  6. Required Terraform configuration live/production/website/ backend.tf terraform { backend "s3" {

    bucket = "my-project-tfstate" region = "eu-west-2" key = "website.tfstate" encrypt = "true" dynamodb_table = "prod-tflock" acl = "bucket-owner-full-control" } } live/production/website/ providers.tf terraform { required_version = "= 1.2.2" required_providers { aws = { version = "~> 4.17" source = "hashicorp/aws" } external = { version = "~> 2.2" source = "hashicorp/external" } } } provider "aws" { region = "eu-west-2" }
  7. Environments, the more the merrier messier ❯ live/ !"" dev

    # !"" networking # $"" website !"" prod # !"" networking # $"" website $"" qa !"" networking $"" website ❯ live/ !"" dev # !"" networking/... # $"" website # !"" backend.tf # !"" datasource.tf # !"" main.tf # !"" outputs.tf # !"" providers.tf # $"" variables.tf !"" prod # !"" networking/... # $"" website # !"" backend.tf # !"" datasource.tf # !"" main.tf # !"" outputs.tf # !"" providers.tf # $"" variables.tf $"" qa !"" networking/... $"" website !"" backend.tf !"" datsource.tf !"" main.tf !"" outputs.tf !"" providers.tf $"" variables.tf
  8. Keeping it DRY with Terragrunt · Define Terraform code once,

    no matter how many environments you have · Gets rid of duplicated backend code · Defines how to manage the Terraform state once in a root directory and inherits it in all child modules.
  9. With Terragrunt ❯ live/ !"" dev # !"" networking/... #

    !"" website-db/... # $"" website-ecs # $"" terragrunt.hcl !"" prod # !"" networking/... # !"" website-db/... # $"" website-ecs # $"" terragrunt.hcl !"" qa # !"" networking/... # !"" website-db/... # $"" website-ecs # $"" terragrunt.hcl $"" terragrunt.hcl
  10. website-ecs/terragrunt.hcl terraform { source = "../../../modules//website-ecs" } include { path

    = find_in_parent_folders("terragrunt.hcl") } dependency "networking" { config_path = "../networking" } dependency "website_db" { config_path = "../website-db" } inputs = { subnet_ids = dependency.networking.outputs.private_subnet_ids vpc_id = dependency.networking.outputs.vpc_id db_name = dependency.website_db.outputs.db_database_name db_endpoint = dependency.website_db.outputs.db_instance_endpoint db_username = dependency.website_db.outputs.db_instance_username }
  11. Benefits of using Terragrunt · Gets rid of repeated Terraform

    config (backend, providers, etc.) · Environment variables support (variables can be populated programmatically) · Automatic resource tagging (applies metadata universally) · Able to execute custom code before or a er running Terraform (before & a er hooks) · Explicit dependencies ("dependency injection") · Makes testing easier (see Terratest)