How to Use Terraform Modules
Introduction Terraform modules are an essential feature for managing infrastructure as code efficiently and at scale. They allow you to group multiple resources and configuration files into reusable, maintainable units. Using modules simplifies your Terraform code, promotes best practices, and enhances collaboration across teams. This tutorial provides a comprehensive guide on how to use Terraform
Introduction
Terraform modules are an essential feature for managing infrastructure as code efficiently and at scale. They allow you to group multiple resources and configuration files into reusable, maintainable units. Using modules simplifies your Terraform code, promotes best practices, and enhances collaboration across teams.
This tutorial provides a comprehensive guide on how to use Terraform modules, covering everything from creating your first module to integrating community modules and optimizing your infrastructure deployments. Whether you are a beginner or an experienced user, mastering modules will improve your Terraform workflow and infrastructure management.
Step-by-Step Guide
1. Understanding Terraform Modules
A Terraform module is a container for multiple resources that are used together. Every Terraform configuration has at least one module, known as the root module, which consists of the resources defined in the main configuration files. Additional modules can be called from the root module to encapsulate reusable logic.
2. Creating a Basic Module
To create your own module, follow these steps:
- Create a directory for your module, e.g.,
modules/network. - Inside the directory, add Terraform configuration files like
main.tf,variables.tf, andoutputs.tf. - Define your resources in
main.tf. For example, create a VPC or subnet resources. - Declare input variables in
variables.tfto parameterize the module. - Define outputs in
outputs.tfto expose useful information to the calling module.
3. Using a Module in Your Root Configuration
Once your module is ready, use it in your root configuration as follows:
module "network" {
source = "./modules/network"
vpc_cidr = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}
The source attribute points to the module path (local directory, Git repo, or Terraform Registry). You then pass the required variables as arguments.
4. Initializing and Applying Terraform
Run these commands in your root configuration directory:
terraform initInitializes the working directory and downloads modules.terraform planShows the changes Terraform will make.terraform applyApplies the changes to your infrastructure.
5. Using Remote Modules
Terraform supports modules hosted remotely, such as:
- Terraform Registry: Official and community modules.
- Git repositories: Public or private repos.
- HTTP URLs: Tarball archives accessible over HTTP.
Example using a module from Terraform Registry:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}
6. Versioning and Module Updates
Always specify module versions when using remote sources to prevent unexpected changes. Use the terraform init -upgrade command to update modules safely.
Best Practices
1. Keep Modules Focused and Small
Design modules to perform a single, clear function. This improves reusability and makes testing easier.
2. Use Input Variables and Outputs Effectively
Parameterize your modules with input variables to make them flexible. Use outputs to expose essential data to the root module or other modules.
3. Avoid Hardcoding Values
Hardcoding values reduces flexibility and reusability. Instead, rely on input variables with sensible defaults.
4. Document Your Modules
Include README files explaining module purpose, inputs, outputs, and usage examples. This facilitates onboarding and collaboration.
5. Use Module Versioning
Pin module versions, especially for remote modules, to ensure stability and predictable deployments.
6. Test Modules Independently
Use tools like terraform validate and terraform plan to test modules. Consider automated testing frameworks such as Terratest.
7. Leverage the Terraform Registry
Use community modules from the Terraform Registry where appropriate to save time and leverage best practices.
Tools and Resources
1. Terraform CLI
The primary tool to write, initialize, plan, and apply your Terraform configurations and modules.
2. Terraform Registry
A centralized repository of publicly available modules that can be used directly or customized.
3. Terratest
An automated testing framework for Terraform modules using Go language, enabling integration and unit testing.
4. Visual Studio Code with Terraform Extensions
Popular IDE with extensions that provide syntax highlighting, linting, and autocompletion for Terraform files.
5. GitHub and GitLab
Version control platforms to store and manage your Terraform modules collaboratively.
6. Sentinel
HashiCorps policy as code framework to enforce governance and compliance on Terraform runs.
Real Examples
Example 1: Creating a Reusable AWS VPC Module
modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
tags = {
Name = var.name
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
cidr_block = var.public_subnets[count.index]
vpc_id = aws_vpc.this.id
map_public_ip_on_launch = true
tags = {
Name = "${var.name}-public-${count.index}"
}
}
modules/vpc/variables.tf
variable "cidr_block" {
description = "The CIDR block for the VPC"
type = string
}
variable "public_subnets" {
description = "List of public subnet CIDR blocks"
type = list(string)
}
variable "name" {
description = "Name tag for resources"
type = string
}
modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.this.id
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
Root module usage:
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
name = "my-vpc"
}
output "vpc_id" {
value = module.vpc.vpc_id
}
Example 2: Using a Community Module from Terraform Registry
Using the popular terraform-aws-modules/vpc/aws module:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.14.0"
name = "example-vpc"
cidr = "10.1.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
public_subnets = ["10.1.1.0/24", "10.1.2.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
}
FAQs
Q1: What is the difference between a root module and a child module?
The root module is the directory where Terraform is initially run, containing your main configuration files. Child modules are reusable modules called from the root module or other modules to organize and modularize your code.
Q2: Can I use modules from private Git repositories?
Yes, Terraform supports modules from private Git repositories. You need to configure authentication (SSH keys or HTTPS credentials) to access private repositories.
Q3: How do I pass variables between modules?
You pass variables to modules via input variables defined in the module and set in the calling configuration. Outputs from one module can be passed as inputs to another.
Q4: How do I handle breaking changes in modules?
Pin module versions to avoid unexpected breaking changes. When upgrading, review the changelog and test thoroughly before applying to production.
Q5: Are modules supported in all Terraform providers?
Yes, modules are a core Terraform feature and work with all providers. The resources inside a module depend on the provider used.
Conclusion
Terraform modules are a powerful means to organize, reuse, and scale your infrastructure code. By encapsulating resources into modular units, you can simplify complex configurations, improve collaboration, and enforce best practices. Whether creating custom modules or leveraging community offerings, mastering modules is key to unlocking Terraforms full potential.
Follow the step-by-step guide, adopt best practices, and use available tools to maximize the benefits of Terraform modules in your infrastructure projects. This approach will lead to cleaner, more maintainable, and scalable infrastructure as code deployments.