DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

LAB: Production Terraform Modules (Local + GitHub + Registry + Multi-Env)

In real companies:

  • You have multiple environments

    • dev
    • stage
    • prod

❌ BAD:

terraform apply (same folder)
β†’ prod overwrites dev
Enter fullscreen mode Exit fullscreen mode

βœ… GOOD (Production):

Separate state per environment
Separate execution per environment
Shared reusable modules
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 2 β€” Final Architecture

terraform-prod-lab/
β”‚
β”œβ”€β”€ modules/                # LOCAL modules
β”‚   └── ec2/
β”‚       β”œβ”€β”€ main.tf
β”‚       β”œβ”€β”€ variables.tf
β”‚       └── outputs.tf
β”‚
β”œβ”€β”€ envs/
β”‚   β”œβ”€β”€ dev/
β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   └── backend.tf
β”‚   β”‚
β”‚   └── prod/
β”‚       β”œβ”€β”€ main.tf
β”‚       └── backend.tf
β”‚
└── README.md
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 3 β€” LOCAL MODULE (modules/ec2)

modules/ec2/main.tf

resource "aws_instance" "this" {
  ami           = var.ami
  instance_type = var.instance_type

  tags = {
    Name = var.name
    Env  = var.env
  }
}
Enter fullscreen mode Exit fullscreen mode

modules/ec2/variables.tf

variable "ami" {}
variable "instance_type" {}
variable "name" {}
variable "env" {}
Enter fullscreen mode Exit fullscreen mode

modules/ec2/outputs.tf

output "instance_id" {
  value = aws_instance.this.id
}
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 4 β€” DEV ENV (LOCAL MODULE CALL)

envs/dev/main.tf

provider "aws" {
  region = "us-east-2"
}

module "ec2_dev" {
  source = "../../modules/ec2"

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  name          = "dev-server"
  env           = "dev"
}
Enter fullscreen mode Exit fullscreen mode

envs/dev/backend.tf

terraform {
  backend "local" {
    path = "dev.tfstate"
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 5 β€” PROD ENV (GITHUB MODULE)

Now simulate production module reuse from GitHub

envs/prod/main.tf

provider "aws" {
  region = "us-east-2"
}

module "ec2_prod" {
  source = "git::https://github.com/your-username/terraform-ec2-module.git"

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  name          = "prod-server"
  env           = "prod"
}
Enter fullscreen mode Exit fullscreen mode

envs/prod/backend.tf

terraform {
  backend "local" {
    path = "prod.tfstate"
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 6 β€” REGISTRY MODULE (ADD S3)

Add real-world registry usage

envs/dev/main.tf (ADD THIS)

module "s3" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = "~> 3.0"

  bucket = "jumptotech-dev-bucket-12345"
}
Enter fullscreen mode Exit fullscreen mode

envs/prod/main.tf (ADD THIS)

module "s3" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = "~> 3.0"

  bucket = "jumptotech-prod-bucket-12345"
}
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 7 β€” RUNNING (CRITICAL PART)

βœ… Deploy DEV

cd envs/dev

terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

βœ… Deploy PROD

cd ../prod

terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ IMPORTANT RESULT

Action What Happens
Apply dev Only dev created
Apply prod Only prod created
Destroy prod Dev stays SAFE
Destroy dev Prod stays SAFE

πŸ‘‰ Because:

Separate state files
Separate folders
Separate execution
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 8 β€” WHY THIS IS PRODUCTION STANDARD

Key Concepts

1. State Isolation

Each environment has:

dev.tfstate
prod.tfstate
Enter fullscreen mode Exit fullscreen mode

So Terraform does NOT mix resources.


2. Module Reuse

Type Example
Local ../../modules/ec2
GitHub git::https://...
Registry terraform-aws-modules

3. No Cross-Environment Impact

Terraform ONLY manages what is in:

current state file
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 9 β€” INTERVIEW QUESTIONS

Q1: How do you prevent dev destroying prod?

Answer:

Separate state files per environment
Separate folders or workspaces
Enter fullscreen mode Exit fullscreen mode

Q2: Where do modules come from?

Local filesystem
Git repositories
Terraform Registry
Enter fullscreen mode Exit fullscreen mode

Q3: Why use GitHub modules?

Version control
Team sharing
Reusable infrastructure
Enter fullscreen mode Exit fullscreen mode

Q4: What is best practice?

Separate repo for modules
Separate repo for environments (infra-live)
Enter fullscreen mode Exit fullscreen mode

πŸ”· PART 10 β€” REAL COMPANY STRUCTURE (VERY IMPORTANT)

infra-modules/        (GitHub repo)
   β”œβ”€β”€ ec2
   β”œβ”€β”€ vpc
   └── rds

infra-live/           (GitHub repo)
   β”œβ”€β”€ dev
   β”œβ”€β”€ stage
   └── prod
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ BONUS β€” WHAT STUDENTS MUST UNDERSTAND

If they remember ONLY ONE thing:

πŸ‘‰ Terraform manages STATE, not resources


πŸ”· PART 11 β€” ADVANCED (OPTIONAL)

Production improvement:

  • Use S3 backend instead of local
  • Add DynamoDB locking
  • Add versions for Git modules

Example:

source = "git::https://github.com/org/module.git?ref=v1.0.0"
Enter fullscreen mode Exit fullscreen mode

βœ… FINAL RESULT

  • Real module usage (ALL 3 types)
  • Production environment separation
  • State isolation
  • GitHub module usage
  • Registry usage
  • Why Terraform does NOT destroy everything

Top comments (0)