A Beginner’s Guide to Terraform Modules: Building Reusable Infrastructure

·

4 min read

Introduction

Infrastructure as Code (IaC) is crucial for managing and automating cloud infrastructure, and Terraform is one of the most popular IaC tools. One of Terraform's key strengths lies in its ability to create reusable components, known as modules, which can simplify your code and promote DRY (Don't Repeat Yourself) principles. In this guide, we'll walk through the basics of Terraform modules and how to use them for reusable infrastructure, complete with starter code.

What Are Terraform Modules?

A Terraform module is a self-contained collection of configuration files that define a set of resources for a specific purpose. Modules allow you to encapsulate common patterns in your infrastructure and reuse them across multiple projects. Essentially, a module is just a directory containing .tf files.

You’ve already been using a module without realizing it—every Terraform configuration has at least one module, which is the root module.

Why Use Modules?

  • Reusability: Write once, use everywhere. You can use the same module across different environments.

  • Consistency: Maintain uniformity across your infrastructure by reusing the same configurations.

  • Simplification: Break complex configurations into smaller, more manageable pieces.

How to Use Terraform Modules

Let’s break it down step by step.

Step 1: Create a Module Directory

Start by creating a directory for your module. Each module should be in its own directory with related configuration files.

mkdir terraform-aws-s3-bucket
cd terraform-aws-s3-bucket
Step 2: Define Resources in the Module

Within the module directory, create a main.tf file to define your resources. For this example, we’ll create an AWS S3 bucket.

# main.tf
resource "aws_s3_bucket" "example" {
  bucket = var.bucket_name
  acl    = var.bucket_acl

  tags = {
    Name        = var.bucket_name
    Environment = var.environment
  }
}
Step 3: Define Variables

Modules typically need input variables to make them flexible and reusable. Create a variables.tf file to define the inputs for your module.

# variables.tf
variable "bucket_name" {
  description = "The name of the S3 bucket"
  type        = string
}

variable "bucket_acl" {
  description = "The ACL of the S3 bucket"
  type        = string
  default     = "private"
}

variable "environment" {
  description = "The environment in which this S3 bucket is deployed"
  type        = string
  default     = "dev"
}
Step 4: Outputs

Sometimes, you’ll want to output information from the module for use in the parent configuration. Create an outputs.tf file.

# outputs.tf
output "bucket_arn" {
  description = "The ARN of the S3 bucket"
  value       = aws_s3_bucket.example.arn
}
Step 5: Use the Module in Your Terraform Configuration

Now, you can use this module in your Terraform configuration. Create a new Terraform configuration in a separate directory.

mkdir terraform-project
cd terraform-project

In your new configuration, you can reference the module like this:

# main.tf
provider "aws" {
  region = "us-west-2"
}

module "s3_bucket" {
  source      = "../terraform-aws-s3-bucket"
  bucket_name = "my-unique-bucket-name"
  environment = "prod"
}

The source parameter tells Terraform where to find the module. In this case, it's a relative path. You can also reference modules from the Terraform Registry, a GitHub repository, or an S3 bucket.

Step 6: Initialize and Apply

Finally, you can initialize and apply the configuration.

terraform init
terraform apply

Terraform will create the S3 bucket based on the configuration defined in the module, and the outputs will be displayed.

Best Practices for Terraform Modules

  • Versioning: When using modules, especially from external sources, always specify a version to avoid breaking changes in your infrastructure.

  • Documentation: Document your modules. Provide a README that explains the purpose of the module, its variables, and outputs.

  • Modularity: Keep your modules small and focused. Each module should have a single responsibility, making it easier to manage and debug.

Example: Using Terraform Registry Modules

Terraform's official module registry contains a wide variety of community and HashiCorp-managed modules. Here's how you can use a public module from the Terraform Registry.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "3.0.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-west-1a", "us-west-1b", "us-west-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 = true
}

This example shows how easy it is to use a pre-built module to deploy a VPC, allowing you to focus on your application rather than the underlying infrastructure.

Conclusion

Terraform modules are a powerful tool for creating reusable, scalable infrastructure. By encapsulating your configurations into modules, you can simplify your code, enforce consistency, and make your infrastructure more maintainable. Whether you’re using your own modules or leveraging the vast number of community modules available, they will help you build and manage infrastructure more efficiently.

Now that you have a basic understanding of Terraform modules, you can start building reusable components in your cloud infrastructure, saving time and reducing complexity in the process. Happy Terraforming!