Skip to main content

Command Palette

Search for a command to run...

Advanced Terraform Module Usage: Versioning, Nesting, and Reuse Across Environments

Updated
4 min read
Advanced Terraform Module Usage: Versioning, Nesting, and Reuse Across Environments

Day 9: Continuing Reuse of Infrastructure with Modules

Welcome back to our Terraform learning journey! On Day 9, we’re diving deeper into module reuse, exploring module gotchas, versioning, and multi-environment deployments. We’ll also enhance our existing module with versioning support and deploy it across different environments. Reading: Module Gotchas & Versioning (Chapter 4, Pages 115-139)

Activity

Enhance my main.tf to support multiple multiple environments

terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region

  default_tags {
    tags = var.tags
  }
}

locals {
  name_prefix = "${var.environment}-web"

  common_tags = merge(var.tags, {
    Environment = var.environment
    ManagedBy   = "terraform"
  })
}

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

module "security_group" {
  source = "./modules/security_group"

  environment = var.environment
  name_prefix = local.name_prefix
  tags        = local.common_tags
}

module "ec2" {
  source            = "./modules/ec2"
  environment       = var.environment
  name_prefix       = local.name_prefix
  ami_id            = data.aws_ami.amazon_linux.id
  instance_type     = var.instance_type[var.environment]
  security_group_id = module.security_group.security_group_id
  tags              = local.common_tags
}

module "alb" {
  source            = "./modules/alb"
  environment       = var.environment
  name_prefix       = local.name_prefix
  security_group_id = module.security_group.security_group_id
  instance_id       = module.ec2.instance_id
  tags              = local.common_tags
}

output "public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = module.ec2.public_ip
}

output "public_dns" {
  description = "Public DNS name of the EC2 instance"
  value       = module.ec2.public_dns
}

output "alb_dns_name" {
  description = "DNS name of the Application Load Balancer"
  value       = module.alb.alb_dns_name
}

output "environment" {
  description = "Current environment"
  value       = var.environment
}

The variables.tf

variable "environment" {
  description = "Environment name (dev, staging, production)"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "Environment must be dev, staging, or production."
  }
}

variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-west-2"
}

variable "instance_type" {
  description = "EC2 instance type per environment"
  type        = map(string)
  default = {
    dev        = "t3.micro"
    staging    = "t3.small"
    production = "t3.medium"
  }
}

variable "min_size" {
  description = "Minimum number of instances per environment"
  type        = map(number)
  default = {
    dev        = 1
    staging    = 2
    production = 3
  }
}

variable "max_size" {
  description = "Maximum number of instances per environment"
  type        = map(number)
  default = {
    dev        = 2
    staging    = 4
    production = 6
  }
}

variable "tags" {
  description = "Common tags for all resources"
  type        = map(string)
  default     = {}
}

And set up environments/terraform.tfvars for dev/staging/production

environment = "dev" / "prod"/ "staging"
aws_region  = "us-west-2"

tags = {
  Environment = "development"
  Project     = "30-day-terraform-challenge"
  Owner       = "simi-ops"
  CostCenter  = "engineering"
}

And ec2.tf to support the environments

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

locals {
  module_version = "1.0.0"
  instance_name  = "${var.name_prefix}-instance"
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  vpc_security_group_ids = [var.security_group_id]

  user_data = base64encode(templatefile("${path.module}/user_data.sh", {
    environment = var.environment
  }))

  tags = merge(var.tags, {
    Name          = local.instance_name
    Module        = "ec2"
    ModuleVersion = local.module_version
  })
}

This repository contains an enhanced Terraform configuration with support for multiple environments (dev, staging, production) and module versioning.

Repository Structure

terraform/
├── main.tf                     
├── variables.tf                
├── deploy.sh                   
├── README.md                   
├── environments/               
│   ├── dev/
│   │   └── terraform.tfvars
│   ├── staging/
│   │   └── terraform.tfvars
│   └── production/
│       └── terraform.tfvars
├── modules/                   
│   ├── alb/                   
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── ec2/                   
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── user_data.sh
│   └── security_group/       
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf

Features

  • Multi-environment support (dev, staging, production)

  • Module versioning with consistent tagging

  • Environment-specific configurations

  • Automated deployment scripts

  • Cost optimization with environment-specific instance types

  • Security best practices with environment-specific access controls

  • Consistent resource naming with environment prefixes

Initialize Terraform

# Make script executable
chmod +x deploy.sh

# Deploy to different environments
./deploy.sh dev plan
./deploy.sh dev apply   
./deploy.sh staging plan
./deploy.sh staging apply
./deploy.sh production plan
./deploy.sh production apply

Environment Differences

EnvironmentInstance TypeRegionSSH AccessALB Protection
devt3.microus-west-20.0.0.0/0Disabled
stagingt3.smallus-west-20.0.0.0/0Disabled
productiont3.mediumus-east-110.0.0.0/8Enabled

Module Versions

All modules are tagged with version 1.0.0 and include:

  • Consistent variable interfaces

  • Comprehensive outputs

  • Environment-aware configurations

  • Proper resource tagging

Cleanup

To remove all resources:

./scripts/deploy.sh dev destroy
./scripts/deploy.sh staging destroy
./scripts/deploy.sh production destroy

More from this blog

Simi Cloud and DevOps

20 posts