Building a EKS Cluster with Terraform: A Modular and Scalable Approach
akhil mittal
Posted on November 14, 2024
Below is a production-standard folder structure for Terraform to provision EKS across multiple environments using modules. The structure ensures modularity, environment separation, and reusability. Additionally, I'll provide steps and pipeline code for deploying this infrastructure using both GitHub Actions and Jenkins.
Production-Standard Terraform Folder Structure
terraform/
├── modules/ # Reusable modules
│ ├── eks/ # EKS module
│ │ ├── main.tf # EKS resource definitions
│ │ ├── variables.tf # Input variables
│ │ ├── outputs.tf # Output values
│ │ ├── versions.tf # Required providers and versions
│ └── vpc/ # VPC module
│ ├── main.tf # VPC resource definitions
│ ├── variables.tf # Input variables
│ ├── outputs.tf # Output values
│ ├── versions.tf # Required providers and versions
├── envs/ # Per-environment configurations
│ ├── dev/ # Development environment
│ │ ├── main.tf # Environment-specific resources
│ │ ├── variables.tf # Environment-specific variables
│ │ ├── backend.tf # S3/DynamoDB backend for Terraform state
│ │ └── tfvars.json # Environment-specific variable values
│ ├── staging/ # Staging environment
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── backend.tf
│ │ └── tfvars.json
│ └── prod/ # Production environment
│ ├── main.tf
│ ├── variables.tf
│ ├── backend.tf
│ └── tfvars.json
└── pipelines/ # CI/CD pipelines for Terraform
├── github-actions.yml # GitHub Actions workflow
└── jenkins-pipeline.groovy # Jenkins pipeline script
Key Files
1. modules/eks/main.tf
Defines EKS cluster and related resources:
resource "aws_eks_cluster" "this" {
name = var.cluster_name
role_arn = var.cluster_role_arn
vpc_config {
subnet_ids = var.subnet_ids
}
}
resource "aws_eks_node_group" "this" {
cluster_name = aws_eks_cluster.this.name
node_role_arn = var.node_role_arn
subnet_ids = var.subnet_ids
scaling_config {
desired_size = var.desired_size
max_size = var.max_size
min_size = var.min_size
}
}
2. envs/dev/main.tf
Calls the EKS module and other required modules (e.g., VPC):
module "vpc" {
source = "../../modules/vpc"
cidr_block = var.cidr_block
env = var.env
}
module "eks" {
source = "../../modules/eks"
cluster_name = var.cluster_name
cluster_role_arn = var.cluster_role_arn
node_role_arn = var.node_role_arn
subnet_ids = module.vpc.subnet_ids
desired_size = var.desired_size
max_size = var.max_size
min_size = var.min_size
}
3. envs/dev/backend.tf
Defines remote backend configuration for state storage:
terraform {
backend "s3" {
bucket = "your-terraform-state-bucket"
key = "eks/dev/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-lock-table"
encrypt = true
}
}
4. envs/dev/tfvars.json
Environment-specific values:
{
"cluster_name": "eks-dev",
"cidr_block": "10.0.0.0/16",
"desired_size": 2,
"max_size": 5,
"min_size": 1,
"env": "dev",
"cluster_role_arn": "arn:aws:iam::123456789012:role/EKS-Cluster-Role",
"node_role_arn": "arn:aws:iam::123456789012:role/EKS-Node-Role"
}
Steps to Deploy Using GitHub Actions
1. GitHub Actions Workflow (pipelines/github-actions.yml
)
name: Deploy Terraform
on:
push:
branches:
- main
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: Terraform Init
run: |
cd terraform/envs/dev
terraform init
- name: Terraform Plan
run: |
cd terraform/envs/dev
terraform plan -var-file=tfvars.json
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: |
cd terraform/envs/dev
terraform apply -auto-approve -var-file=tfvars.json
Steps to Deploy Using Jenkins
2. Jenkins Pipeline Script (pipelines/jenkins-pipeline.groovy
)
pipeline {
agent any
environment {
TF_VAR_AWS_ACCESS_KEY = credentials('aws-access-key-id')
TF_VAR_AWS_SECRET_KEY = credentials('aws-secret-access-key')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Terraform Init') {
steps {
sh '''
cd terraform/envs/dev
terraform init
'''
}
}
stage('Terraform Plan') {
steps {
sh '''
cd terraform/envs/dev
terraform plan -var-file=tfvars.json
'''
}
}
stage('Terraform Apply') {
steps {
input "Apply changes?"
sh '''
cd terraform/envs/dev
terraform apply -auto-approve -var-file=tfvars.json
'''
}
}
}
}
How to Use
With GitHub Actions:
- Push changes to the
main
branch to trigger the workflow. - Review the GitHub Actions logs for progress.
With Jenkins:
- Trigger the pipeline manually or on code commits.
- Approve the
Terraform Apply
stage if required.
Key Considerations
-
State Management:
- Ensure the S3 bucket and DynamoDB table for state locking are created beforehand.
-
Environment Variables:
- Use environment variables for sensitive information like AWS keys.
-
Separate Environments:
- Use different
backend.tf
configurations for dev, staging, and prod.
- Use different
-
IAM Roles:
- Attach least-privilege IAM roles for Terraform execution.
This setup ensures a robust and modular approach to managing infrastructure across environments. Let me know if you need further assistance!
Posted on November 14, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.