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
- 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.
- 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.
- Simplified Collaboration: Teams can work on different modules independently, allowing for parallel development and reduced risk of conflicts.
- 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.
- 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.
Leave a Reply