The Terraform Toolkit: Spinning Up an EKS Cluster


Creating an Amazon EKS (Elastic Kubernetes Service) cluster using Terraform involves a series of carefully orchestrated steps. Each step can be encapsulated within its own Terraform module for better modularity and reusability. Here’s a breakdown of how to structure your Terraform project to deploy an EKS cluster on AWS.

1. VPC Module

  • Create a Virtual Private Cloud (VPC): This is where your EKS cluster will reside.
  • Set Up Subnets: Establish both public and private subnets within the VPC to segregate your resources effectively.

2. EKS Module

  • Deploy the EKS Cluster: Link the components created in the VPC module to your EKS cluster.
  • Define Security Rules: Set up security groups and rules for both the EKS master nodes and worker nodes.
  • Configure IAM Roles: Create IAM roles and policies needed for the EKS master and worker nodes.

Project Directory Structure

Let’s begin by creating a root project directory named terraform-eks-project. Below is the suggested directory structure for the entire Terraform project:

terraform-eks-project/
│
├── modules/                    # Root directory for all modules
│   ├── vpc/                    # VPC module: VPC, Subnets (public & private)
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   │
│   └── eks/                    # EKS module: cluster, worker nodes, IAM roles, security groups
│       ├── main.tf
│       ├── variables.tf
│       ├── outputs.tf
│       └── worker_userdata.tpl
│
├── backend.tf                  # Backend configuration (e.g., S3 for remote state)
├── main.tf                     # Main file to call and stitch modules together
├── variables.tf                # Input variables for the main configuration
├── outputs.tf                  # Output values from the main configuration
├── provider.tf                 # Provider block for the main configuration
├── terraform.tfvars            # Variable definitions file
└── README.md                   # Documentation and instructions

Root Configuration Files Overview

  • backend.tf: Specifies how Terraform state is managed and where it’s stored (e.g., in an S3 bucket).
  • main.tf: The central configuration file that integrates the various modules and manages the AWS resources.
  • variables.tf: Declares the variables used throughout the project.
  • outputs.tf: Manages the outputs from the Terraform scripts, such as IDs and ARNs.
  • terraform.tfvars: Contains user-defined values for the variables.
  • README.md: Provides documentation and usage instructions for the project.

Backend Configuration (backend.tf)

The backend.tf file is responsible for defining how Terraform state is loaded and how operations are executed. For instance, using an S3 bucket as the backend allows for secure and durable state storage.

terraform {
  backend "s3" {
    bucket  = "my-terraform-state-bucket"      # Replace with your S3 bucket name
    key     = "path/to/my/key"                 # Path to the state file within the bucket
    region  = "us-west-1"                      # AWS region of your S3 bucket
    encrypt = true                             # Enable server-side encryption of the state file

    # Optional: DynamoDB for state locking and consistency
    dynamodb_table = "my-terraform-lock-table" # Replace with your DynamoDB table name

    # Optional: If S3 bucket and DynamoDB table are in different AWS accounts or need specific credentials
    # profile = "myprofile"                    # AWS CLI profile name
  }
}

Main Configuration (main.tf)

The main.tf file includes module declarations for the VPC and EKS components.

VPC Module

The VPC module creates the foundational network infrastructure components.

module "vpc" {
  source                = "./modules/vpc"            # Location of the VPC module
  env                   = terraform.workspace        # Current workspace (e.g., dev, prod)
  app                   = var.app                    # Application name or type
  vpc_cidr              = lookup(var.vpc_cidr_env, terraform.workspace)  # CIDR block specific to workspace
  public_subnet_number  = 2                          # Number of public subnets
  private_subnet_number = 2                          # Number of private subnets
  db_subnet_number      = 2                          # Number of database subnets
  region                = var.aws_region             # AWS region

  # NAT Gateways settings
  vpc_enable_nat_gateway = var.vpc_enable_nat_gateway  # Enable/disable NAT Gateway
  enable_dns_hostnames = true                         # Enable DNS hostnames in the VPC
  enable_dns_support   = true                         # Enable DNS resolution in the VPC
}

EKS Module

The EKS module sets up a managed Kubernetes cluster on AWS.

module "eks" {
  source                               = "./modules/eks"
  env                                  = terraform.workspace
  app                                  = var.app
  vpc_id                               = module.vpc.vpc_id
  cluster_name                         = var.cluster_name
  cluster_service_ipv4_cidr            = lookup(var.cluster_service_ipv4_cidr, terraform.workspace)
  public_subnets                       = module.vpc.public_subnet_ids
  cluster_version                      = var.cluster_version
  cluster_endpoint_private_access      = var.cluster_endpoint_private_access
  cluster_endpoint_public_access       = var.cluster_endpoint_public_access
  cluster_endpoint_public_access_cidrs = var.cluster_endpoint_public_access_cidrs
  sg_name                              = var.sg_external_eks_name
}

Outputs Configuration (outputs.tf)

The outputs.tf file defines the values that Terraform will output after applying the configuration. These outputs can be used for further automation or simply for inspection.

output "vpc_id" {
  value = module.vpc.vpc_id
}

output "cluster_id" {
  value = module.eks.cluster_id
}

output "cluster_arn" {
  value = module.eks.cluster_arn
}

output "cluster_certificate_authority_data" {
  value = module.eks.cluster_certificate_authority_data
}

output "cluster_endpoint" {
  value = module.eks.cluster_endpoint
}

output "cluster_version" {
  value = module.eks.cluster_version
}

Variable Definitions (terraform.tfvars)

The terraform.tfvars file is where you define the values for variables that Terraform will use.

aws_region = "us-east-1"

# VPC Core
vpc_cidr_env = {
  "dev" = "10.101.0.0/16"
  #"test" = "10.102.0.0/16"
  #"prod" = "10.103.0.0/16"
}
cluster_service_ipv4_cidr = {
  "dev" = "10.150.0.0/16"
  #"test" = "10.201.0.0/16"
  #"prod" = "10.1.0.0/16"
}

enable_dns_hostnames   = true
enable_dns_support     = true
vpc_enable_nat_gateway = false

# EKS Configuration
cluster_name                         = "test_cluster"
cluster_version                      = "1.27"
cluster_endpoint_private_access      = true
cluster_endpoint_public_access       = true
cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]
sg_external_eks_name                 = "external_kubernetes_sg"

Variable Declarations (variables.tf)

The variables.tf file is where you declare all the variables used in your Terraform configuration. This allows for flexible and reusable configurations.

variable "aws_region" {
  description = "Region in which AWS Resources to be created"
  type        = string
  default     = "us-east-1"
}

variable "zone" {
  description = "The zone where VPC is"
  type        = list(string)
  default     = ["us-east-1a", "us-east-1b"]
}

variable "azs" {
  type        = list(string)
  description = "List of availability zones suffixes."
  default     = ["a", "b", "c"]
}

variable "app" {
  description = "The APP name"
  default     = "ekstestproject"
}

variable "env" {
  description = "The Environment variable"
  type        = string
  default     = "dev"
}
variable "vpc_cidr_env" {}
variable "cluster_service_ipv4_cidr" {}

variable "enable_dns_hostnames" {}
variable "enable_dns_support" {}

# VPC Enable NAT Gateway (True or False)
variable "vpc_enable_nat_gateway" {
  description = "Enable NAT Gateways for Private Subnets Outbound Communication"
  type        = bool
  default     = true
}

# VPC Single NAT Gateway (True or False)
variable "vpc_single_nat_gateway" {
  description = "Enable only single NAT Gateway in one Availability Zone to save costs during our demos"
  type        = bool
  default     = true
}

# EKS Variables
variable "cluster_name" {
  description = "The EKS cluster name"
  default     = "k8s"
}
variable "cluster_version" {
  description = "The Kubernetes minor version to use for the

 EKS cluster (for example 1.26)"
  type        = string
  default     = null
}

variable "cluster_endpoint_private_access" {
  description = "Indicates whether the Amazon EKS private API server endpoint is enabled."
  type        = bool
  default     = false
}

variable "cluster_endpoint_public_access" {
  description = "Indicates whether the Amazon EKS public API server endpoint is enabled."
  type        = bool
  default     = true
}

variable "cluster_endpoint_public_access_cidrs" {
  description = "List of CIDR blocks which can access the Amazon EKS public API server endpoint."
  type        = list(string)
  default     = ["0.0.0.0/0"]
}

variable "sg_external_eks_name" {
  description = "The SG name."
}

Conclusion

This guide outlines the key components of setting up an Amazon EKS cluster using Terraform. By organizing your Terraform code into reusable modules, you can efficiently manage and scale your infrastructure across different environments. The modular approach not only simplifies management but also promotes consistency and reusability in your Terraform configurations.