HomeRoadmapsTerraform Day 5
DevOps Track Β· Day 5 HCL Iteration Β· 20 min

Dynamic Code & Loops
DevOps Terraform Sprint β€” Day 5

Leverage count, for_each maps, and dynamic blocks for automated container networks and volume mounts

πŸ› οΈ Tooling: HCL for_each & Map Expressions🎭 Role: DevOps & Infrastructure Quality Engineer
TerraformHCL Loopsfor_eachcountDocker Networks
About Today's 20-Minute Lab

Declaring multiple environments or services individually leads to redundant code blocks. Today on Day 5, you will master HCL iteration constructs: for_each map expressions, count index loops, and dynamic nested blocks to spin up dynamic container clusters and networks cleanly.

🎬
Day 5 Video WalkthroughComing Soon

An interactive 20-minute video walkthrough for Day 5 is currently in production. Follow the step-by-step interactive playbook below!

πŸ“¦Sample Codebase & Working Solution (Day 5)Available Now
View on GitHub

The verified Day 5 sample code is live in the public GitHub repository. Clone it to get the complete working solution immediately.

Git Clone β€” Available Now
git clone https://github.com/letstrnsfrm-ai/devops-terraform-roadmap.git
cd devops-terraform-roadmap/day-5-dynamic-code
1

Iterating Over Services with for_each

GOAL
Define a map of microservice specifications and provision containers using for_each.
MAIN.TF FOR_EACH
Create main.tf using map iteration:
HCL β€” main.tf
terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

# Map of microservices configuration
locals {
  services = {
    web = {
      image = "nginx:alpine"
      port  = 8088
    }
    cache = {
      image = "redis:alpine"
      port  = 6379
    }
  }
}

# Image resources using for_each
resource "docker_image" "service_images" {
  for_each = local.services
  name     = each.value.image
}

# Container resources using for_each
resource "docker_container" "microservices" {
  for_each = local.services
  name     = "qe_${each.key}_service"
  image    = docker_image.service_images[each.key].image_id

  ports {
    internal = 80
    external = each.value.port
  }
}
🏭Production Context & Enterprise Real-World Implementation
πŸ’‘ Why We Are Doing This: `for_each` creates stable map key addresses (e.g. `docker_container.microservices['web']`). Unlike array `count`, removing an item from a map does not trigger accidental destruction of adjacent resources.
🏒 Real-World Production Usecase: Production platforms (like Netflix or Lyft) manage dynamic clusters of microservices via maps. Adding or removing a service from a `locals.services` map dynamically provisions or destroys only that specific service.
βš™οΈ How Implemented in Production: Production modules use `for_each = var.subnets` to dynamically create multi-AZ subnets, IAM role bindings, and Kubernetes namespaces without hardcoding repetitive resource blocks.
2

Dynamic Nested Blocks for Docker Networks

GOAL
Construct dynamic Docker network connections using nested dynamic "networks_advanced" blocks.
DYNAMIC NETWORKS
Add custom Docker bridge network and dynamic attachment blocks:
HCL β€” Dynamic Network Block
resource "docker_network" "custom_bridge" {
  name = "qe_custom_bridge_network"
}

# Example of dynamic nested block declaration
resource "docker_container" "dynamic_service" {
  name  = "qe_dynamic_networked_app"
  image = "nginx:alpine"

  dynamic "networks_advanced" {
    for_each = [docker_network.custom_bridge.name]
    content {
      name = networks_advanced.value
    }
  }

  ports {
    internal = 80
    external = 8089
  }
}
🏭Production Context & Enterprise Real-World Implementation
πŸ’‘ Why We Are Doing This: Dynamic blocks allow nested configuration blocks (like security group rules, ingress routes, or volume mounts) to be constructed dynamically based on complex data structures.
🏒 Real-World Production Usecase: Enterprise cloud security teams configure complex VPC Security Groups dynamically using `dynamic 'ingress'` blocks driven by firewall rule lists.
βš™οΈ How Implemented in Production: Production Terraform code uses `dynamic 'ingress'` and `dynamic 'subnet'` blocks to generate multi-region routing tables and container volume mounts conditionally.
3

Provisioning & Map Output Extraction

GOAL
Apply the dynamic HCL blueprint and extract container IP addresses using `for` expressions in `outputs.tf`.
OUTPUTS.TF
Create `outputs.tf` using `for` comprehension loops:
HCL β€” outputs.tf
output "service_endpoints" {
  value = {
    for k, v in docker_container.microservices : k => "http://localhost:${v.ports[0].external}"
  }
  description = "Map of microservice names to local endpoint URLs"
}
APPLY WORKFLOW
Before applying, ensure your Docker daemon is running:
Terminal β€” Docker Daemon Setup (choose your OS)
# macOS β€” Docker Desktop (GUI: open app) OR Colima (CLI):
colima start
export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"

# Windows β€” ensure Docker Desktop is running with WSL2 backend

# Linux:
sudo systemctl start docker
Then run Terraform init and apply:
Terminal β€” Init & Apply
terraform init
terraform apply -auto-approve
🏭Production Context & Enterprise Real-World Implementation
πŸ’‘ Why We Are Doing This: HCL `for` comprehension expressions transform complex resource state objects into clean key-value dictionary outputs consumed by external systems.
🏒 Real-World Production Usecase: Service discovery platforms (like Consul or Kubernetes CoreDNS) consume Terraform output maps to register dynamic container IP addresses automatically.
βš™οΈ How Implemented in Production: In production pipelines, `for` expressions filter and extract active database connection strings into Kubernetes secrets or HashiCorp Vault entries.
4

Cluster Verification & Teardown

GOAL
Verify all dynamically provisioned endpoints via curl and inspect output map structure.
CLUSTER CHECK
Wait for containers to settle, then test web endpoint and output map:
Terminal β€” Output Map & Endpoint Check
# Display generated endpoint map
terraform output

# Allow container port binding to settle
sleep 2

# macOS / Linux β€” Curl Web Service (Port 8088)
curl -I http://localhost:8088

# macOS / Linux β€” Curl Dynamic Networked App (Port 8089)
curl -I http://localhost:8089

# Windows PowerShell equivalent:
# Invoke-WebRequest -Uri http://localhost:8088
# Invoke-WebRequest -Uri http://localhost:8089

# Clean up all dynamic resources
terraform destroy -auto-approve
EXPECTED OUTPUT
Verification Success
service_endpoints = {"cache" = "http://localhost:6379", "web" = "http://localhost:8088"}
HTTP/1.1 200 OK returned by dynamically provisioned web container.
🏭Production Context & Enterprise Real-World Implementation
πŸ’‘ Why We Are Doing This: Batch validation verifies that all dynamically iterated resources are healthy and responding over network interfaces before closing deployment gates.
🏒 Real-World Production Usecase: Microservice platforms verify that all dynamic replicas across multi-container pods respond with healthy status codes during rolling updates.
βš™οΈ How Implemented in Production: Automated test runners iterate over the output map, executing concurrent HTTP health probes and latency audits against all generated microservice endpoints.