Terraform Modules with Versioning: A Comprehensive Guide
Terraform, an Infrastructure as Code (IaC) tool, has changed the landscape of infrastructure automation. Modules in Terraform allow users to encapsulate a group of resources and use them as a single unit, making IaC more maintainable and reusable. This post walks through the creation of a Terraform module for EC2 deployment, versioning, best practices, and finally, integrating GitHub Actions for CI/CD.
1. Creating the Terraform EC2 Module
Directory Structure:
my-ec2-module/
|-- main.tf
|-- outputs.tf
|-- variables.tf
|-- README.md
main.tf:
resource "aws_instance" "this" {
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = var.instance_name
}
}
variables.tf:
variable "ami_id" {
description = "The AMI ID for the EC2 instance"
type = string
}
variable "instance_type" {
description = "The type of the EC2 instance"
type = string
default = "t2.micro"
}
variable "instance_name" {
description = "The name tag of the EC2 instance"
type = string
default = "MyEC2Instance"
}
outputs.tf:
output "instance_id" {
value = aws_instance.this.id
}
2. Versioning Your Module
Once you’ve created your module, push it to a version control system like GitHub. Use semantic versioning (e.g., v1.0.0) for your module releases. This allows users of your module to pin to specific versions, ensuring consistency.
3. Calling Your Terraform Module with Versioning
In your main Terraform configuration:
module "ec2_instance" {
source = "git::https://github.com/your-username/my-ec2-module?ref=v1.0.0"
ami_id = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
instance_name = "MyProdServer"
}
4. Backend Configuration & State File Locking
For safety and collaboration, use remote backends like Amazon S3 and enable state locking with DynamoDB.
backend.tf:
terraform {
backend "s3" {
bucket = "my-terraform-backend-bucket"
key = "path/to/my/key"
region = "us-west-1"
dynamodb_table = "my-lock-table"
encrypt = true
}
}
5. Best Practices
- Always use
terraform fmtfor consistent formatting. - Implement
terraform validateto validate configurations. - Use
.terraform-versionwith tfenv to ensure consistent Terraform versions across the team. - Secure sensitive data with
terraform.tfvarsand.gitignore.
6. GitHub Action for Terraform
.github/workflows/terraform.yml:
name: "Terraform"
on:
pull_request:
paths:
- 'terraform/**'
jobs:
terraform:
name: "Terraform Plan & Apply"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_version: 1.0.3
- name: Terraform Init
run: terraform init
- name: Terraform Plan
run: terraform plan
continue-on-error: true
- name: Wait for Approval
uses: actions/github-script@v3
with:
script: |
await github.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
event: "COMMENT",
body: "Check the Terraform plan and approve the workflow to proceed."
});
await github.pulls.requestReviewers({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
reviewers: ["your-reviewer-username"]
});
- name: Terraform Apply
if: github.event.review.state == 'approved'
run: terraform apply -auto-approve
Note: Replace "your-reviewer-username" with the actual GitHub username of the person who should approve.
Conclusion
With this guide, you now have a foundational understanding of creating, versioning, and deploying Terraform modules. Integrating Terraform with GitHub Actions ensures a streamlined and efficient Infrastructure as Code workflow. As always, make sure to test in a safe environment before rolling out any IaC changes.



Pingback: Terraform-Version File