⚡Terraform Modules: All you need to know

⚡Terraform Modules: All you need to know

Hey Folks! In this article, I will explain about Terraform modules with examples.

If you have not read my previous article on Terraform complete basics, go checkout and share your thoughts.

Now, let's begin with Terraform modules.

Terraform modules are reusable units of infrastructure code that encapsulate a set of resources and their configurations.

They allow you to abstract and package infrastructure components into logical groups, providing a way to define, configure, and manage resources as a single entity.

Modules can be created by users or obtained from the Terraform Module Registry, a repository of community-contributed modules.

Benefits of Using Terraform Modules

Using modules in Terraform offers several benefits:

  1. Reusability: Modules promote code reuse by encapsulating infrastructure components into self-contained units. This eliminates the need to repeat resource configurations across multiple projects, reducing duplication and improving maintainability.

  2. Abstraction: Modules provide an abstraction layer, allowing you to define and interact with infrastructure resources at a higher level of granularity. This simplifies the management and understanding of complex infrastructure setups.

  3. Scalability: Modules enable you to scale your infrastructure by reusing and composing smaller, modular components. This allows you to manage larger deployments more effectively and promotes consistency across different environments.

  4. Isolation: Modules provide an isolated and encapsulated environment for managing specific resources. This isolation helps avoid conflicts between different parts of the infrastructure and makes it easier to reason about the behavior and dependencies of each module.

  5. Collaboration: Modules can be shared and reused across teams and projects, fostering collaboration and knowledge sharing. By providing a standardized way to define and provision infrastructure, modules facilitate teamwork and improve productivity.

Structure of a Terraform Module

A Terraform module typically consists of a collection of resource definitions, input variables, and output values. Let's explore each of these components:

  1. Resource Definitions: A module encapsulates a set of resources that are logically related. These resources can be provisioned and managed as a single unit. For example, a module could define a complete AWS VPC, including subnets, security groups, and routing rules.

  2. Input Variables: Modules expose input variables, which allow users to customize the behavior and configuration of the module. Input variables can be used to specify values such as resource names, IP addresses, or instance sizes. They provide flexibility and make modules more reusable across different environments.

  3. Output Values: Modules can also define output values, which represent information that can be retrieved and used by other parts of the infrastructure. Output values can include, for instance, the ID of a provisioned resource, an IP address, or a DNS name. Other modules or the main Terraform configuration can then reference these outputs.

Using Terraform Modules

To use a module in your Terraform configuration, you need to instantiate it by providing values for the input variables.

This is done using the module block, where you define the source of the module and set the values for the input variables. Let's illustrate this with an example:

module "vpc" {
  source = "github.com/example/vpc"

  vpc_cidr = "10.0.0.0/16"
  subnet_cidr = "10.0.1.0/24"
  instance_type = "t3.micro"
}

In this example, we're instantiating a module named "vpc" from a module source located in a GitHub repository. We provide values for the input variables vpc_cidr, subnet_cidr, and instance_type.

Module Composition

Terraform modules can be composed together to create more complex infrastructure setups. For example, you could create a higher-level module that combines multiple lower-level modules.

This composition allows you to build on existing modules and create a hierarchy of reusable components.

module "network" {
  source = "github.com/example/network"

  vpc_cidr = "10.0.0.0/16"
  subnet_cidr = "10.0.1.0/24"
}

module "web_server" {
  source = "github.com/example/web-server"

  instance_type = "t3.micro"
  subnet_id = module.network.subnet_id
}

In this composition example, we instantiate a "network" module and a "web_server" module. The "web_server" module references the subnet_id output value of the "network" module, allowing it to be provisioned within the correct subnet.

Scenario

Imagine you are building an infrastructure for a web application on AWS using Terraform. You need to provision a Virtual Private Cloud (VPC), a set of subnets, security groups, and EC2 instances.

Instead of defining all these resources in a single Terraform configuration file, you can use modules to organize and encapsulate related resources.

Let's start by creating a module for the VPC. Create a directory named "vpc" and create a file named "main.tf" inside it. In this file, define the VPC and its associated resources:

# vpc/main.tf

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr
}

resource "aws_subnet" "public_subnet" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.public_subnet_cidr
  availability_zone       = "us-east-1a"
}

resource "aws_subnet" "private_subnet" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.private_subnet_cidr
  availability_zone       = "us-east-1b"
}

resource "aws_internet_gateway" "gateway" {
  vpc_id = aws_vpc.main.id
}

resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gateway.id
  }
}

resource "aws_route_table_association" "public_association" {
  subnet_id      = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_route_table.id
}

In this module, we have defined a VPC, a public subnet, a private subnet, an internet gateway, a public route table, and associated the public subnet with the public route table.

Next, let's create a module for the EC2 instances. Create a directory named "ec2" and create a file named "main.tf" inside it. In this file, define the EC2 instances and their associated resources:

# ec2/main.tf

resource "aws_security_group" "web_sg" {
  name        = "web_sg"
  description = "Security group for web instances"
  vpc_id      = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web_instance" {
  ami           = var.ami_id
  instance_type = var.instance_type
  subnet_id     = var.subnet_id
  vpc_security_group_ids = [
    aws_security_group.web_sg.id
  ]
}

output "public_ip" {
  value = aws_instance.web_instance.public_ip
}

In this module, we have defined a security group for the web instances, an EC2 instance using the specified AMI and instance type, and associated the instance with the specified subnet and security group.

We have also defined an output value "public_ip" to expose the public IP address of the EC2 instance.

Now that we have created the modules, we can use them in our main Terraform configuration. Create a file named "main.tf" in the root directory:

# main.tf

module "vpc" {
  source = "./vpc"

  vpc_cidr               = "10.0.0.0/16"
  public_subnet_cidr     = "10.0.1.0/24"
  private_subnet_cidr    = "10.0.2.0/24"
}

module "ec2" {
  source = "./ec2"

  vpc_id           = module.vpc.aws_vpc_main.id
  subnet_id        = module.vpc.aws_subnet_public_subnet.id
  ami_id           = "ami-12345678"
  instance_type    = "t2.micro"
}

In this main configuration file, we are using the modules we created. We specify the module source as the local directories where the modules are located. We also provide the necessary input variables for each module.

Now, when you run terraform apply in the root directory, Terraform will provision the VPC and EC2 instances according to the configurations defined in the modules.

Using modules, you have encapsulated the VPC and EC2 resources into separate modules, making your Terraform configuration more modular, reusable, and maintainable.

If you need to create multiple instances or modify the VPC configuration, you can simply update the input variables in the main configuration file without modifying the module definitions.

Additionally, modules can be shared with others by publishing them to the Terraform Module Registry or using source control repositories like GitHub. This allows the community to benefit from pre-built modules and encourages collaboration and best practice sharing.

Summary

Remember, Terraform modules are a powerful way to organize, reuse, and share infrastructure code. By leveraging different module types, you can create modular, scalable, and maintainable infrastructure-as-code deployments.

Happy Terraforming!