DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

Advanced Terraform Lab (Production Style)

Topics covered:

  • for_each
  • map variables
  • locals
  • dynamic blocks
  • terraform workspaces
  • multi-environment deployment

Goal

Deploy multiple EC2 servers with different configurations using:

  • for_each
  • map variables
  • locals
  • dynamic blocks
  • terraform workspaces

Architecture

DEV

1 EC2 instance
t2.micro
Enter fullscreen mode Exit fullscreen mode

PROD

3 EC2 instances
t2.small
Enter fullscreen mode Exit fullscreen mode

Security group rules created dynamically.


Step 1 — Create Project

mkdir terraform-advanced-lab
cd terraform-advanced-lab
Enter fullscreen mode Exit fullscreen mode

Create files

main.tf
variables.tf
outputs.tf
Enter fullscreen mode Exit fullscreen mode

Step 2 — variables.tf

Introduce map and list data types.

variable "aws_region" {
  type = string
  default = "us-east-2"
}

variable "instances" {
  description = "EC2 instances configuration"
  type = map(object({
    instance_type = string
    name          = string
  }))
}

variable "security_ports" {
  type = list(number)
}
Enter fullscreen mode Exit fullscreen mode

This introduces students to complex data structures.

Example structure:

map(object({
instance_type
name
}))
Enter fullscreen mode Exit fullscreen mode

Step 3 — main.tf

Provider configuration.

provider "aws" {
  region = var.aws_region
}
Enter fullscreen mode Exit fullscreen mode

Get Latest AMI

data "aws_ami" "amazon_linux" {

  most_recent = true
  owners = ["amazon"]

  filter {
    name = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4 — Locals

Locals help create environment logic.

locals {

  environment = terraform.workspace

  instance_config = local.environment == "prod" ? {

    web1 = {
      instance_type = "t2.small"
      name = "prod-web1"
    }

    web2 = {
      instance_type = "t2.small"
      name = "prod-web2"
    }

    web3 = {
      instance_type = "t2.small"
      name = "prod-web3"
    }

  } : {

    web1 = {
      instance_type = "t2.micro"
      name = "dev-web1"
    }

  }

}
Enter fullscreen mode Exit fullscreen mode

This is real enterprise logic.

Environment decides infrastructure size.


Step 5 — Security Group

resource "aws_security_group" "web_sg" {

  name = "web-security-group"

  dynamic "ingress" {

    for_each = var.security_ports

    content {

      from_port = ingress.value
      to_port   = ingress.value
      protocol  = "tcp"
      cidr_blocks = ["0.0.0.0/0"]

    }

  }

}
Enter fullscreen mode Exit fullscreen mode

This uses dynamic blocks.

If ports list is:

[22,80,443]
Enter fullscreen mode Exit fullscreen mode

Terraform creates 3 ingress rules automatically.


Step 6 — EC2 Instances using for_each

resource "aws_instance" "web" {

  for_each = local.instance_config

  ami           = data.aws_ami.amazon_linux.id
  instance_type = each.value.instance_type

  vpc_security_group_ids = [
    aws_security_group.web_sg.id
  ]

  tags = {
    Name = each.value.name
    Environment = local.environment
  }

}
Enter fullscreen mode Exit fullscreen mode

Important:

Concept Meaning
for_each creates resources from map
each.key map key
each.value map value

Example Terraform creates:

aws_instance.web["web1"]
aws_instance.web["web2"]
aws_instance.web["web3"]
Enter fullscreen mode Exit fullscreen mode

Step 7 — outputs.tf

output "instance_public_ips" {

  value = {
    for instance in aws_instance.web :
    instance.tags.Name => instance.public_ip
  }

}
Enter fullscreen mode Exit fullscreen mode

Example output:

prod-web1 = 18.120.x.x
prod-web2 = 3.19.x.x
prod-web3 = 54.193.x.x
Enter fullscreen mode Exit fullscreen mode

Step 8 — Initialize Terraform

terraform init
Enter fullscreen mode Exit fullscreen mode

Step 9 — Create Workspaces

DEV workspace

terraform workspace new dev
Enter fullscreen mode Exit fullscreen mode

Switch

terraform workspace select dev
Enter fullscreen mode Exit fullscreen mode

Deploy

terraform apply
Enter fullscreen mode Exit fullscreen mode

Result:

1 EC2 instance
Enter fullscreen mode Exit fullscreen mode

Step 10 — Create PROD Environment

Create workspace

terraform workspace new prod
Enter fullscreen mode Exit fullscreen mode

Switch

terraform workspace select prod
Enter fullscreen mode Exit fullscreen mode

Deploy

terraform apply
Enter fullscreen mode Exit fullscreen mode

Result:

3 EC2 instances
Enter fullscreen mode Exit fullscreen mode

Step 11 — Verify Workspaces

terraform workspace list
Enter fullscreen mode Exit fullscreen mode

Output

default
dev
prod
Enter fullscreen mode Exit fullscreen mode

What Students Learn

This lab teaches real production Terraform skills:

Concept Why Important
for_each used in almost every real Terraform project
locals simplify environment logic
dynamic blocks avoid repeated code
maps & objects advanced variable types
workspaces multi-environment infrastructure

DevOps Interview Questions from this Lab

1️⃣ Difference between count vs for_each

2️⃣ What is terraform workspace

3️⃣ What are locals

4️⃣ What are dynamic blocks

5️⃣ When should you use map vs list

6️⃣ Why is for_each safer than count

Top comments (0)