DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

functions, count, for_each, dynamic blocks, and production-style structure,

1. Project Structure (Production Style)

terraform-devops-lab/
│
├── main.tf
├── provider.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
│
├── security.tf
├── instances.tf
└── data.tf
Enter fullscreen mode Exit fullscreen mode

Terraform reads all .tf files together, but we separate them for clean architecture.


2. provider.tf

Provider configuration and Terraform settings.

terraform {

  required_version = ">= 1.5"

  required_providers {

    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }

    local = {
      source  = "hashicorp/local"
      version = "~> 2.4"
    }

  }
}

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

3. variables.tf

Defines inputs.

variable "aws_region" {
  type = string
}

variable "environment" {
  type = string
}

variable "instance_types" {

  type = map(string)

  default = {
    dev  = "t2.micro"
    prod = "t2.small"
  }

}

variable "servers" {

  type = list(string)

}

variable "ports" {

  type = list(number)

}
Enter fullscreen mode Exit fullscreen mode

4. terraform.tfvars

Provides values.

aws_region = "us-east-2"

environment = "dev"

servers = [
  "web",
  "api",
  "worker"
]

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

5. data.tf

Production Terraform never hardcodes AMIs.

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

6. security.tf

Security group with dynamic block.

resource "aws_security_group" "web" {

  name = "${var.environment}-web-sg"

  dynamic "ingress" {

    for_each = var.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 automatically creates rules for:

22
80
443
Enter fullscreen mode Exit fullscreen mode

7. instances.tf

Using both count and for_each.

Count Example

resource "aws_instance" "count_servers" {

  count = length(var.servers)

  ami           = data.aws_ami.amazon_linux.id
  instance_type = lookup(var.instance_types,var.environment)

  vpc_security_group_ids = [aws_security_group.web.id]

  tags = {

    Name = format(
      "%s-count-%s",
      var.environment,
      element(var.servers,count.index)
    )

  }

}
Enter fullscreen mode Exit fullscreen mode

Functions used here:

length()
lookup()
element()
format()
Enter fullscreen mode Exit fullscreen mode

for_each Example

resource "aws_instance" "foreach_servers" {

  for_each = toset(var.servers)

  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t2.micro"

  vpc_security_group_ids = [aws_security_group.web.id]

  tags = {

    Name = "${var.environment}-foreach-${each.value}"

  }

}
Enter fullscreen mode Exit fullscreen mode

8. main.tf

Local resource with timestamp()

resource "local_file" "deployment_info" {

  filename = "deployment.txt"

  content = format(
    "Terraform deployment time: %s",
    timestamp()
  )

}
Enter fullscreen mode Exit fullscreen mode

9. outputs.tf

Terraform outputs.

output "server_count" {

  value = length(var.servers)

}

output "security_group_id" {

  value = aws_security_group.web.id

}

output "deployment_time" {

  value = timestamp()

}
Enter fullscreen mode Exit fullscreen mode

10. Commands Practice

Initialize providers

terraform init -upgrade
Enter fullscreen mode Exit fullscreen mode

Create execution plan

terraform plan -out=infra.plan
Enter fullscreen mode Exit fullscreen mode

Apply saved plan

terraform apply infra.plan
Enter fullscreen mode Exit fullscreen mode

Target specific resource

terraform plan -target=local_file.deployment_info
terraform apply -target=local_file.deployment_info
terraform destroy -target=local_file.deployment_info
Enter fullscreen mode Exit fullscreen mode

Create only security group

terraform apply -target=aws_security_group.web
Enter fullscreen mode Exit fullscreen mode

Force recreation

terraform taint aws_instance.count_servers[0]
Enter fullscreen mode Exit fullscreen mode

Show outputs

terraform output
Enter fullscreen mode Exit fullscreen mode

Show dependency graph

terraform graph
Enter fullscreen mode Exit fullscreen mode

Generate infrastructure diagram

terraform graph | dot -Tpng > graph.png
Enter fullscreen mode Exit fullscreen mode

11. Architecture Created

           Data Source
        (Latest Amazon AMI)
                │
                ▼
        Security Group
        Dynamic Rules
      22 / 80 / 443
                │
                ▼
        EC2 Instances
        count + for_each
                │
                ▼
        Local File
       deployment.txt
                │
                ▼
             Outputs
Enter fullscreen mode Exit fullscreen mode

12. Why This Lab Is Production-Ready

This lab teaches real Terraform patterns:

  • dynamic infrastructure
  • environment configuration
  • reusable variables
  • data sources
  • dependency graph
  • count vs for_each
  • tfvars separation
  • organized file structure

This is very close to how Terraform is used in DevOps teams.

Top comments (0)