5.0 KiB
5) Build & Reuse a Simple Module (25 min)
In this section, you’ll turn repeated EC2 logic into a reusable Terraform module.
Modules make your code DRY (Don’t Repeat Yourself), easier to test, and simpler to use across teams and environments.
What is a module?
A module is just a folder that contains Terraform configuration files (.tf).
Your root module (the folder where you run the CLI) can call other modules from:
- A local path (
./modules/ec2-instance) - A Git repo (
git::https://...), or - A registry (
registry.terraform.io)
Here we’ll use a local module.
Step 1: Create the project & module folder
mkdir -p ~/terraform-modules-lab/modules/ec2-instance
cd ~/terraform-modules-lab
- Creates a workspace with a nested folder
modules/ec2-instancethat will contain reusable EC2 code.
Your tree will look like:
terraform-modules-lab/
main.tf # root (calls the module)
modules/
ec2-instance/
variables.tf
main.tf # module implementation
outputs.tf
Step 2: Define module inputs (variables)
Create modules/ec2-instance/variables.tf:
variable "instance_type" { description = "Type of EC2 instance"; default = "t2.micro" }
variable "instance_name" { description = "Tag name for instance" }
variable "instance_count" { description = "Number of EC2"; default = 1 }
- These are inputs the module expects.
defaultmakes inputs optional (callers can override).- You can add stronger typing & validation for safety:
variable "instance_type" { type = string description = "EC2 size" default = "t2.micro" validation { condition = can(regex("^t[23]\.", var.instance_type)) error_message = "Use a t2.* or t3.* instance for this lab." } }
Step 3: Implement the module logic
Create modules/ec2-instance/main.tf:
resource "aws_instance" "this" {
count = var.instance_count
ami = "ami-0e6329e222e662a52"
instance_type = var.instance_type
tags = { Name = "${var.instance_name}-${count.index}" }
}
- Uses
countto create N instances with a single block. tags.Nameincludes thecount.indexsuffix so each instance has a unique name (e.g.,App-Server-0,App-Server-1).
Note on AMIs: AMI IDs are region-specific. We use an Amazon Linux 2 AMI for ap-south-1 (Mumbai). If you switch regions, update this AMI or fetch it dynamically (e.g., with a data source).
Step 4: Expose useful outputs
Create modules/ec2-instance/outputs.tf:
output "instance_ids" { value = [for i in aws_instance.this : i.id] }
output "public_ips" { value = [for i in aws_instance.this : i.public_ip] }
- Makes it easy for callers to consume important info (IDs, IPs).
- The
forexpression collects values from the resource instances created viacount.
Step 5: Call the module from the root
Create the root main.tf at ~/terraform-modules-lab/main.tf:
provider "aws" { region = "ap-south-1" }
module "ec2_instance" {
source = "./modules/ec2-instance"
instance_type = "t2.micro"
instance_name = "App-Server"
instance_count = 2
}
sourcepoints to the local path of your module folder.- Inputs (
instance_type,instance_name,instance_count) are set by the caller (the root module). - You can define multiple module blocks to create different groups of instances, or use
.tfvarsfiles for environments.
Step 6: Initialize and apply
terraform init
terraform apply -auto-approve
terraform initdownloads providers and fetches module sources (local/Git/registry).terraform applycreates 2 EC2 instances namedApp-Server-0andApp-Server-1in ap-south-1.
After the apply, view outputs:
terraform output
You should see lists for instance_ids and public_ips.
How to reuse this module elsewhere
- Copy the
modules/ec2-instancefolder into any Terraform project and call it withsource = "./modules/ec2-instance". - Or publish the module to a Git repo and reference with
source = "git::https://github.com/yourorg/yourrepo//modules/ec2-instance?ref=v1.0.0". - Standardize inputs/outputs so teams can use it without reading internals.
Best practices
- Version control your modules (Git tags) to avoid breaking changes.
- Add README.md inside the module with usage examples and input/output docs.
- Prefer types & validation for variables.
- Keep AMIs parametrized or discover them via a
data "aws_ami"query to avoid hard-coding. - If multiple teams use the same module, consider a private Terraform registry or a Git monorepo with clear versioning.
Cleanup
When done (to avoid charges):
terraform destroy -auto-approve
Summary
You built a reusable EC2 module, exposed clean inputs/outputs, and consumed it from the root.
This pattern scales to VPCs, RDS, ALBs, and more—compose modules like building blocks to create reliable infrastructure at speed.