ad4469dc-7beb-4b7f-90b1-7de.../docs/05_modules_reuse.md

5.0 KiB
Raw Blame History

5) Build & Reuse a Simple Module (25 min)

In this section, youll turn repeated EC2 logic into a reusable Terraform module.
Modules make your code DRY (Dont 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 well 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-instance that 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.
  • default makes 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 count to create N instances with a single block.
  • tags.Name includes the count.index suffix 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 for expression collects values from the resource instances created via count.

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
}
  • source points 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 .tfvars files for environments.

Step 6: Initialize and apply

terraform init
terraform apply -auto-approve
  • terraform init downloads providers and fetches module sources (local/Git/registry).
  • terraform apply creates 2 EC2 instances named App-Server-0 and App-Server-1 in 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-instance folder into any Terraform project and call it with source = "./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.