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 fmt
for consistent formatting. - Implement
terraform validate
to validate configurations. - Use
.terraform-version
with tfenv to ensure consistent Terraform versions across the team. - Secure sensitive data with
terraform.tfvars
and.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