Terraform_modules
Chapter 37: Terraform Modules
Section titled “Chapter 37: Terraform Modules”This chapter covers creating, using, and managing Terraform modules for reusable infrastructure.
What are Modules?
Section titled “What are Modules?”Modules are containers for multiple resources that are used together.
┌─────────────────────────────────────────────────────────────────────────────┐│ Terraform Module Concept │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ Without Modules (Monolithic) │ ││ │ │ ││ │ main.tf │ ││ │ ┌────────────────────────────────────────────────────────────┐ │ ││ │ │ VPC + Subnets + Security Groups + Instances + RDS │ │ ││ │ └────────────────────────────────────────────────────────────┘ │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ With Modules (Modular) │ ││ │ │ ││ │ main.tf │ ││ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ ││ │ │ module │ │ module │ │ module │ │ module │ │ ││ │ │ "vpc" │ │ "sg" │ │ "ec2" │ │ "rds" │ │ ││ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ ││ Benefits: ││ ✓ Reusability - Write once, use many times ││ ✓ Organization - Better structure and readability ││ ✓ Abstraction - Hide complexity ││ ✓ Versioning - Pin specific versions ││ │└─────────────────────────────────────────────────────────────────────────────┘Creating Modules
Section titled “Creating Modules”Module Structure
Section titled “Module Structure”┌─────────────────────────────────────────────────────────────────────────────┐│ Module Directory Structure │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ module-name/ │ ││ │ │ ││ │ ├── main.tf # Resources │ ││ │ ├── variables.tf # Input variables │ ││ │ ├── outputs.tf # Output values │ ││ │ ├── README.md # Documentation │ ││ │ └── versions.tf # Provider versions │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘Example: VPC Module
Section titled “Example: VPC Module”resource "aws_vpc" "main" { cidr_block = var.cidr_block enable_dns_hostnames = var.enable_dns_hostnames enable_dns_support = var.enable_dns_support
tags = merge( var.tags, { Name = "${var.name}-vpc" } )}
resource "aws_subnet" "public" { count = length(var.availability_zones)
vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(var.cidr_block, 8, count.index) availability_zone = var.availability_zones[count.index] map_public_ip_on_launch = true
tags = merge( var.tags, { Name = "${var.name}-public-${var.availability_zones[count.index]}" } )}
resource "aws_subnet" "private" { count = length(var.availability_zones)
vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(var.cidr_block, 8, count.index + 10) availability_zone = var.availability_zones[count.index]
tags = merge( var.tags, { Name = "${var.name}-private-${var.availability_zones[count.index]}" } )}
resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id
tags = merge( var.tags, { Name = "${var.name}-igw" } )}variable "name" { description = "Name prefix for resources" type = string}
variable "cidr_block" { description = "VPC CIDR block" type = string default = "10.0.0.0/16"}
variable "availability_zones" { description = "Availability zones" type = list(string) default = ["us-east-1a", "us-east-1b"]}
variable "enable_dns_hostnames" { description = "Enable DNS hostnames" type = bool default = true}
variable "enable_dns_support" { description = "Enable DNS support" type = bool default = true}
variable "tags" { description = "Tags to apply to resources" type = map(string) default = {}}output "vpc_id" { description = "ID of the VPC" value = aws_vpc.main.id}
output "vpc_cidr" { description = "CIDR block of the VPC" value = aws_vpc.main.cidr_block}
output "public_subnet_ids" { description = "IDs of public subnets" value = aws_subnet.public[*].id}
output "private_subnet_ids" { description = "IDs of private subnets" value = aws_subnet.private[*].id}
output "igw_id" { description = "ID of the Internet Gateway" value = aws_internet_gateway.main.id}Using Modules
Section titled “Using Modules”┌─────────────────────────────────────────────────────────────────────────────┐│ Module Sources │├─────────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ Module Source Types │ ││ │ │ ││ │ Local: module "vpc" { │ ││ │ source = "./modules/vpc" │ ││ │ } │ ││ │ │ ││ │ Terraform Registry: module "vpc" { │ ││ │ source = "terraform-aws-modules/vpc/aws" │ ││ │ version = "3.0.0" │ ││ │ } │ ││ │ │ ││ │ Git: module "vpc" { │ ││ │ source = "github.com/org/repo//modules/vpc" │ ││ │ } │ ││ │ │ ││ │ S3/GCS: module "vpc" { │ ││ │ source = "s3::https://bucket.s3.amazonaws.com/modules/vpc" │ ││ │ } │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────────────┘Using the VPC Module
Section titled “Using the VPC Module”provider "aws" { region = "us-east-1"}
module "vpc" { source = "./modules/vpc"
name = "prod" cidr_block = "10.0.0.0/16" availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
tags = { Project = "MyApp" Environment = "Production" }}
# Use module outputsresource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro" subnet_id = module.vpc.public_subnet_ids[0]
tags = { Name = "WebServer" }}Registry Modules
Section titled “Registry Modules”Using AWS VPC Module
Section titled “Using AWS VPC Module”# Using official AWS VPC modulemodule "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.0.0"
name = "my-vpc" cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true single_nat_gateway = false
tags = { Terraform = "true" Environment = "prod" }}Using Other Registry Modules
Section titled “Using Other Registry Modules”# RDS Modulemodule "rds" { source = "terraform-aws-modules/rds/aws" version = "6.0.0"
identifier = "my-database"
engine = "mysql" engine_version = "8.0" family = "mysql8.0"
allocated_storage = 20 max_allocated_storage = 100
instance_class = "db.t3.micro" multi_az = true
username = "admin" password = "mypassword"
vpc_id = module.vpc.vpc_id subnet_ids = module.vpc.private_subnets
backup_retention_period = 7 skip_final_snapshot = false}Module Composition
Section titled “Module Composition”┌─────────────────────────────────────────────────────────────────────────────┐│ Module Composition Example │├─────────────────────────────────────────────────────────────────────────────┤│ ││ Root Module ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ main.tf │ ││ │ │ ││ │ module "network" { │ ││ │ source = "./modules/network" │ ││ │ } │ ││ │ │ ││ │ module "compute" { │ ││ │ source = "./modules/compute" │ ││ │ vpc_id = module.network.vpc_id │ ││ │ subnet_ids = module.network.private_subnet_ids │ ││ │ security_group = module.network.default_sg │ ││ │ } │ ││ │ │ ││ │ module "database" { │ ││ │ source = "./modules/database" │ ││ │ vpc_id = module.network.vpc_id │ ││ │ subnet_ids = module.network.private_subnet_ids │ ││ │ } │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ ││ Benefits: ││ ✓ Independent modules can be developed ││ ✓ Outputs from one module feed into others ││ ✓ Team can work on different modules ││ │└─────────────────────────────────────────────────────────────────────────────┘Module Versioning
Section titled “Module Versioning”# Pin exact versionmodule "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.0.0"
name = "my-vpc" cidr = "10.0.0.0/16"}
# Version constraintsmodule "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 3.0" # Any 3.x version
name = "my-vpc" cidr = "10.0.0.0/16"}
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = ">= 3.0.0, < 4.0.0" # Range
name = "my-vpc" cidr = "10.0.0.0/16"}Nested Modules
Section titled “Nested Modules”# Root modulemodule "app" { source = "./modules/app"
vpc_id = module.network.vpc_id subnet_ids = module.network.private_subnet_ids}
# modules/app/main.tfmodule "web" { source = "./web"
vpc_id = var.vpc_id subnet_ids = var.subnet_ids}
module "api" { source = "./api"
vpc_id = var.vpc_id subnet_ids = var.subnet_ids}Module Debugging
Section titled “Module Debugging”# Get module pathterraform console > module.web.module.ec2.aws_instance.main
# List all resources including modulesterraform state list
# Show module outputterraform output -module=module.vpc
# Verbose outputTF_LOG=DEBUG terraform applySummary
Section titled “Summary”In this chapter, you learned:
- Module Concept: What are modules and why use them
- Creating Modules: Structure, variables, outputs
- Using Modules: Local, registry, git sources
- Registry Modules: Using pre-built modules
- Module Composition: Connecting modules together
- Versioning: Pinning and constraining versions