Deploying infrastructure to multiple environments using Terraform modules
Deploying infrastructure to multiple environments using Terraform modules involves a structured approach to organizing and managing your Terraform code. This guide will walk you through a detailed example of how to set up and deploy complex infrastructure configurations across different environments, including development (dev), quality assurance (QA), staging, and production (prod). We'll cover security, networking, and other considerations in depth.
Step 1: Setting Up Terraform Modules for Multi-Environment Deployment
Organizing Terraform Modules
Terraform modules are reusable components that encapsulate infrastructure configurations. To deploy to multiple environments, you'll create separate modules for each environment. This approach allows you to manage environment-specific configurations and variables efficiently.
- Directory Structure:
infrastructure/
environments/
dev/
main.tf
variables.tf
qa/
main.tf
variables.tf
staging/
main.tf
variables.tf
prod/
main.tf
variables.tf
modules/
network/
main.tf
variables.tf
compute/
main.tf
variables.tf
storage/
main.tf
variables.tf
- Module Structure:
Each environment directory (
dev
,qa
,staging
,prod
) contains amain.tf
file that defines the infrastructure for that environment.The
variables.tf
file in each environment directory defines environment-specific variables.The
modules
directory contains reusable modules for network, compute, and storage configurations.
- Defining Environment Variables:
- In
variables.tf
of each environment, define variables specific to that environment. For example, indev/
variables.tf
:
variable "environment" {
type = string
default = "dev"
}
variable "instance_type" {
type = string
default = "t2.micro"
}
- Defining Modules:
- In
modules/network/
main.tf
, define a network module:
resource "aws_vpc" "this" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "this" {
cidr_block = "10.0.1.0/24"
vpc_id = aws_vpc.this.id
availability_zone = "us-west-2a"
}
- Using Modules in Environments:
- In
dev/
main.tf
, use the network module:
module "network" {
source = file("./modules/network")
}
Managing Variables Across Environments
Environment-Specific Variables:
- Use environment-specific variables in your modules. For example, in
modules/compute/
main.tf
:
- Use environment-specific variables in your modules. For example, in
resource "aws_instance" "this" {
ami = "ami-0c94855ba95c71c99"
instance_type = var.instance_type
}
Overriding Variables:
- In
prod/
variables.tf
, you can override theinstance_type
variable:
- In
variable "instance_type" {
type = string
default = "t2.large"
}
Step 2: Configuring Complex Infrastructure with Terraform
Configuring Networks
VPC and Subnets:
- In
modules/network/
main.tf
, define a VPC and subnets:
- In
resource "aws_vpc" "this" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "this" {
cidr_block = "10.0.1.0/24"
vpc_id = aws_vpc.this.id
availability_zone = "us-west-2a"
}
- Security Groups:
- In
modules/network/
main.tf
, define a security group:
resource "aws_security_group" "this" {
name = "allow_tls"
description = "Allow TLS inbound traffic"
vpc_id = aws_vpc.this.id
ingress {
description = "TLS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
Configuring Compute Resources
EC2 Instances:
- In
modules/compute/
main.tf
, define an EC2 instance:
- In
resource "aws_instance" "this" {
ami = "ami-0c94855ba95c71c99"
instance_type = var.instance_type
vpc_security_group_ids = [aws_security_group.this.id]
subnet_id = aws_subnet.this.id
}
Configuring Storage Resources
S3 Buckets:
- In
modules/storage/
main.tf
, define an S3 bucket:
- In
resource "aws_s3_bucket" "this" {
bucket = "my-bucket"
acl = "private"
}
Step 3: Implementing Security and Networking Considerations
Security Considerations
Access Controls:
- Use IAM roles and policies to manage access to your resources. For example, in
modules/compute/
main.tf
:
- Use IAM roles and policies to manage access to your resources. For example, in
resource "aws_iam_role" "this" {
name = "ec2-role"
description = "EC2 role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Principal = {
Service = "ec2.amazonaws.com"
}
Effect = "Allow"
Sid = ""
}
]
})
}
- Encryption:
- Use AWS Key Management Service (KMS) to manage encryption keys. For example, in
modules/storage/
main.tf
:
resource "aws_kms_key" "this" {
description = "S3 bucket encryption key"
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.this.arn
sse_algorithm = "aws:kms"
}
}
}
Networking Considerations
Network Architecture:
- Design a network architecture that segregates resources into different subnets and security groups based on their roles.
Network Segmentation:
- Use subnets and security groups to isolate resources from each other.
Step 4: Deploying and Managing Environments with Terraform
Deploying Environments
Initializing Terraform:
- Navigate to the environment directory (e.g.,
dev
) and run:
- Navigate to the environment directory (e.g.,
terraform init
Applying Terraform Configurations:
- Run:
terraform apply
Managing and Updating Environments
Updating Infrastructure:
- Make changes to your Terraform code and run
terraform apply
again.
- Make changes to your Terraform code and run
Managing State:
- Use Terraform state files to keep track of your infrastructure state.
Troubleshooting:
Use
terraform validate
to check for errors in your configuration.Use
terraform console
to interactively explore your infrastructure state.
Additional Considerations
Version Control
Versioning Terraform Code:
- Use version control systems like Git to manage changes to your Terraform code.
Collaboration
Collaborative Development:
- Use Terraform workspaces to manage multiple environments and collaborate with team members.
Monitoring and Logging
Monitoring Resources:
- Use AWS CloudWatch to monitor your resources.
Logging:
- Use AWS CloudWatch Logs to collect and analyze logs from your resources.
Conclusion
Deploying infrastructure to multiple environments using Terraform modules requires careful planning and organization. By following this guide, you can create a structured approach to managing your infrastructure across different environments, ensuring consistency and security. Remember to consider additional factors like version control, collaboration, and monitoring to ensure the long-term maintainability of your infrastructure.
Subscribe to my newsletter
Read articles from Mohammed Iliyas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Mohammed Iliyas
Mohammed Iliyas
As a seasoned DevOps engineer, I bring a comprehensive set of skills to the table, encompassing version control with Git and GitOps using ArgoCD, containerization with Docker, and orchestration with Kubernetes, Helm, and Istio. I'm proficient in infrastructure provisioning and management using Terraform and Ansible, and have expertise in setting up and managing CI/CD pipelines with Jenkins, Azure Pipelines, and AWS CodePipeline. With extensive experience in cloud platforms, including Azure and AWS, I've deployed and managed applications on Azure Kubernetes Service (AKS) and AWS Elastic Container Service (ECS) and Elastic Container Service for Kubernetes (EKS). Additionally, I've integrated security practices into DevOps pipelines, ensuring secure and compliant software development and deployment. My technical prowess extends to Bash shell scripting, Linux system administration, and programming in Golang. Throughout my journey, I've developed a unique blend of skills that enable me to streamline development, deployment, and management of applications across multiple environments.