# TerraWeek Day-05

# **TerraWeek Day 5: Terraform Modules, Composition, and Versioning**

Welcome back to **TerraWeek Day 5**! In today’s post, we will dive into the core concepts of **Terraform Modules**, **Modular Composition**, and **Module Versioning**. We'll also take a look at how to lock Terraform module versions for stable and consistent infrastructure deployments.

## **Task 1: Understanding Terraform Modules**

### What are Terraform Modules?

In Terraform, **modules** are containers for multiple resources that work together. They encapsulate reusable infrastructure code into units that can be managed and deployed independently.

### Why Do We Need Terraform Modules?

Modules are essential for the following reasons:

* **Reusability**: Write the code once and use it across different projects or environments.
    
* **Consistency**: Standardize infrastructure components, ensuring uniform deployments.
    
* **Abstraction**: Simplify complex configurations by breaking them down into manageable parts.
    
* **Scalability**: Build a modular architecture to scale deployments without rewriting code.
    

### Benefits of Using Modules

1. **Easier Collaboration**: Teams can work on individual modules without interfering with others.
    
2. **Version Control**: Track changes to modules and roll back to previous versions.
    
3. **Reduced Errors**: Standardized modules reduce the chances of configuration errors.
    
4. **Faster Development**: Reusing modules speeds up infrastructure deployments.
    

## **Task 2: Defining a Module in Terraform**

Now, let’s define a **Terraform module** to encapsulate reusable infrastructure configuration. For this example, we’ll create an **EC2 instance in AWS**.

### Directory Structure

```bash
day05
├── main.tf
├── terraform.tf
├── terraform-infra
│   ├── ec2.tf
│   ├── output.tf
│   └── variable.tf
```

### Code for `main.tf` (Root Module)

```css
module "ec2_instance" {
  source         = "./terraform-infra"
  ami_id         = "ami-0e9085e60087ce171"
  instance_type  = "t2.micro"
  instance_name  = "WebServer1"
}

output "instance_public_ip" {
  value = module.ec2_instance.public_ip
}
```

### Code for `terraform-infra/ec2.tf` (EC2 Module)

```css
resource "aws_instance" "web_server" {
  ami           = var.ami_id
  instance_type = var.instance_type

  tags = {
    Name = var.instance_name
  }
}

output "public_ip" {
  value = aws_instance.web_server.public_ip
}
```

### Code for `terraform-infra/variable.tf`

```css
variable "ami_id" {
  description = "The AMI ID to use for the EC2 instance"
  type        = string
}

variable "instance_type" {
  description = "The type of the EC2 instance"
  type        = string
}

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

### Steps to Apply Terraform

1. **Initialize Terraform**:
    
    ```bash
    terraform init
    ```
    
2. **Review the Terraform Plan**:
    
    ```bash
    terraform plan
    ```
    
3. **Apply Changes**:
    
    ```bash
    terraform apply --auto-approve
    ```
    
4. **Verify the EC2 Instance**: You will see the public IP of the EC2 instance in the output.
    

### Final Output of EC2 Instance

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1734506704600/7de04523-c39e-437a-8a95-9f6878a21436.png align="center")

## **Task 3: Modular Composition and Versioning**

### Modular Composition

In Terraform, **modular composition** allows you to nest modules, creating hierarchical structures for better organization. Let’s update our `main.tf` file to deploy two EC2 instances with shared configurations.

### Updated `main.tf` (with Composition)

```css
module "ec2_instance1" {
    source         = "./terraform-infra"
    ami_id         = "ami-0e9085e60087ce171"
    instance_type  = "t2.micro"
    instance_name  = "WebServer1"
}

module "ec2_instance2" {
    source         = "./terraform-infra"
    ami_id         = module.ec2_instance1.ami_id
    instance_type  = module.ec2_instance1.instance_type
    instance_name  = "WebServer2"
}

output "instance1_public_ip" {
    value = module.ec2_instance1.public_ip
}

output "instance2_public_ip" {
    value = module.ec2_instance2.public_ip
}
```

This configuration creates two EC2 instances with shared configurations, showcasing the concept of modular composition.

### Output of Two EC2 Instances

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1734506744496/ab88f75c-9b09-4f3d-adbe-8c3ee9ec53ae.png align="center")

### Module Versioning

When using modules in Terraform, you may want to lock the version of a module to ensure consistent deployments. Here are some ways to lock module versions:

1. **Fixed Version**:
    
    ```css
    module "example" {
      source  = "terraform-aws-modules/vpc/aws"
      version = "2.78.0"
    }
    ```
    
2. **Version Range**:
    
    ```css
    module "example" {
      source  = "terraform-aws-modules/vpc/aws"
      version = "~> 2.0"
    }
    ```
    
    This allows patch updates but not major updates.
    
3. **Git Repository with Commit Hash**:
    
    ```css
    module "example" {
      source = "git::https://github.com/example/module.git?ref=abc123"
    }
    ```
    
4. **Git Tag or Branch**:
    
    ```css
    module "example" {
      source = "git::https://github.com/example/module.git?ref=v1.0.0"
    }
    ```
    

These methods ensure that the module version remains consistent, preventing unexpected changes when modules are updated.

## **Task 4: Locking Terraform Module Versions**

### Why Lock Module Versions?

Locking module versions ensures that the infrastructure deployed by Terraform is predictable and stable, avoiding issues that may arise from updates or breaking changes in a module.

### Ways to Lock Terraform Module Versions:

1. **Specify a Fixed Version**:
    
    ```css
    module "example" {
      source  = "terraform-aws-modules/vpc/aws"
      version = "2.78.0"
    }
    ```
    
2. **Version Range**:
    
    ```css
    module "example" {
      source  = "terraform-aws-modules/vpc/aws"
      version = "~> 2.0"
    }
    ```
    
3. **Git Repository with Commit Hash**:
    
    ```css
    module "example" {
      source = "git::https://github.com/example/module.git?ref=abc123"
    }
    ```
    
4. **Git Tag or Branch**:
    
    ```css
    module "example" {
      source = "git::https://github.com/example/module.git?ref=v1.0.0"
    }
    ```
    

By locking module versions, you ensure that your infrastructure is consistently deployed with the same code, reducing the risk of unexpected changes.

---

## Checkout Github repo (if needed) : [https://github.com/Amitabh-DevOps/TerraWeek/tree/feat/day05/day05](https://github.com/Amitabh-DevOps/TerraWeek/tree/feat/day05/day05)

---

**Conclusion**  
In today’s lesson, we covered the essential concepts of **Terraform modules**, **modular composition**, and **module versioning**. By using modules, you can build scalable, reusable, and maintainable infrastructure code that promotes consistency and collaboration within your team. Locking module versions is also crucial to ensure that your infrastructure remains stable across different environments.

---

Feel free to share your thoughts in the comments below or reach out if you have any questions!  
Also, don’t forget to check out my [LinkedIn](https://www.linkedin.com/in/amitabh-devops/) profile for more updates on my DevOps journey. Happy Terraforming! 🌍
