The Importance of Using Modules in a Multi-Module Terraform Structure

The Importance of Using Modules in a Multi-Module Terraform Structure

Terraform is widely recognized for managing infrastructure as code (IaC). Using modules to structure your Terraform scripts is a best practice that enhances code reusability, maintainability, and scalability. In a complex infrastructure, organizing modules into a multi-module structure allows you to manage separate components more efficiently. This article explains the benefits of using modules in Terraform and provides an example of a multi-module setup for creating a Virtual Machine (VM) on Google Cloud Platform (GCP).

Benefits of a Multi-Module Terraform Structure

  1. Modularization Enhances Reusability: By dividing infrastructure components into reusable modules, you avoid code duplication and create reusable infrastructure components that can be used across different projects and environments.
  2. Improved Maintainability and Organization: A multi-module structure organizes your Terraform codebase, making it easier to manage and troubleshoot. Each module serves a specific function, such as networking, compute, or storage.
  3. Simplified Collaboration: Teams can work on different modules independently, allowing for parallel development and reduced risk of conflicts.
  4. Flexibility and Scalability: Modules provide a flexible way to scale infrastructure as they can be customized and deployed multiple times with different parameters, offering a robust approach to scaling.
  5. Consistent Best Practices: Modules help enforce consistent best practices for infrastructure provisioning, such as input validation, resource naming conventions, and tagging strategies.

Example of a Multi-Module Terraform Structure for GCP

Let’s build a multi-module Terraform structure to manage different components of infrastructure on GCP, such as networks, subnets, and VMs. Each component will be managed by its own module.

Project Directory Structure

terraform-gcp-infra/
│
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   ├── network/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── vm/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
  • main.tf: The root configuration that calls the modules.
  • modules/: A directory containing the network and VM modules.
  • network/: A module to create a network and subnets.
  • vm/: A module to create a VM instance.

1. Defining the Network Module

modules/network/main.tf

resource "google_compute_network" "vpc_network" {
  name = var.network_name
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "subnet" {
  name          = var.subnet_name
  ip_cidr_range = var.subnet_cidr
  region        = var.region
  network       = google_compute_network.vpc_network.name
}

modules/network/variables.tf

variable "network_name" {
  description = "The name of the VPC network."
  type        = string
}

variable "subnet_name" {
  description = "The name of the subnet."
  type        = string
}

variable "subnet_cidr" {
  description = "The CIDR range for the subnet."
  type        = string
}

variable "region" {
  description = "The GCP region for the resources."
  type        = string
}

modules/network/outputs.tf

output "network_name" {
  value = google_compute_network.vpc_network.name
}

output "subnet_name" {
  value = google_compute_subnetwork.subnet.name
}

2. Defining the VM Module

modules/vm/main.tf

provider "google" {
  project = var.project_id
  region  = var.region
}

resource "google_compute_instance" "vm_instance" {
  name         = var.instance_name
  machine_type = var.machine_type
  zone         = var.zone

  boot_disk {
    initialize_params {
      image = var.image
    }
  }

  network_interface {
    network    = var.network
    subnetwork = var.subnetwork
    access_config {}
  }

  tags = var.tags
}

modules/vm/variables.tf

variable "project_id" {
  description = "The GCP project ID"
  type        = string
}

variable "region" {
  description = "The GCP region"
  type        = string
}

variable "zone" {
  description = "The GCP zone"
  type        = string
}

variable "instance_name" {
  description = "The name of the VM instance"
  type        = string
}

variable "machine_type" {
  description = "The machine type for the VM"
  type        = string
  default     = "e2-medium"
}

variable "image" {
  description = "The image for the VM boot disk"
  type        = string
}

variable "network" {
  description = "The network to deploy the VM"
  type        = string
}

variable "subnetwork" {
  description = "The subnetwork to deploy the VM"
  type        = string
}

variable "tags" {
  description = "List of tags to apply to the VM"
  type        = list(string)
  default     = []
}

modules/vm/outputs.tf

output "instance_name" {
  value = google_compute_instance.vm_instance.name
}

output "instance_self_link" {
  value = google_compute_instance.vm_instance.self_link
}

3. Root Module Configuration

main.tf

provider "google" {
  project = "your-gcp-project-id"
  region  = "us-central1"
}

module "network" {
  source       = "./modules/network"
  network_name = "my-vpc-network"
  subnet_name  = "my-subnet"
  subnet_cidr  = "10.0.0.0/16"
  region       = "us-central1"
}

module "vm_instance" {
  source        = "./modules/vm"
  project_id    = "your-gcp-project-id"
  region        = "us-central1"
  zone          = "us-central1-a"
  instance_name = "my-vm"
  machine_type  = "e2-medium"
  image         = "debian-cloud/debian-11"
  network       = module.network.network_name
  subnetwork    = module.network.subnet_name
  tags          = ["web", "prod"]
}

Conclusion

Organizing your Terraform scripts into a multi-module structure simplifies code management and promotes reusability, scalability, and collaboration across teams. By using modules for components like networks and VMs, you maintain a clean, modular codebase that is easy to understand, test, and manage. This approach leads to more efficient and reliable infrastructure management in cloud environments like GCP.

Julio Dutra Avatar

Leave a Reply

Your email address will not be published. Required fields are marked *