Create an EKS Cluster Using Terraform

In this blog, we’ll explore how to create an EKS cluster using a Terraform module, including setting up a node group, , ECR, ACM, and other core components.

Amazon EKS (Elastic Kubernetes Service) provides a managed Kubernetes service that makes it …


This content originally appeared on DEV Community and was authored by Ravindra Singh

In this blog, we’ll explore how to create an EKS cluster using a Terraform module, including setting up a node group, , ECR, ACM, and other core components.

Amazon EKS (Elastic Kubernetes Service) provides a managed Kubernetes service that makes it easy to run Kubernetes on AWS without needing to manage your own control plane.

Prerequisites
Before you begin, ensure that you have the following tools installed:

  • Terraform: Install Terraform by following the official installation guide.
  • AWS CLI: Install and configure the AWS CLI by following the AWS CLI installation guide.
  • kubectl: Install kubectl for interacting with your EKS cluster by following the kubectl installation guide.

Let’s Begin😎
👉🏻** What are Terraform modules?**
A Terraform module is a set of organized configuration files within a specific directory. These modules bundle together resources focused on a particular task, helping to minimize the amount of code you need to write for similar infrastructure components.

Here is the structure for that.

Step1: Clone the Repository
🧑🏻‍💻git clone https://github.com/ravindrasinghh/Kubernetes-Playlist.git
👨🏻‍💻cd Kubernetes-Playlist/Lesson1/

Step 2: Initialize Terraform

  1. terraform init

  2. terraform plan

  3. terraform apply

👉🏻acm.tf

module "acm_backend" {
  source      = "terraform-aws-modules/acm/aws"
  version     = "4.0.1"
  domain_name = "codedevops.cloud"
  subject_alternative_names = [
    "*.codedevops.cloud"
  ]
  zone_id             = data.aws_route53_zone.main.id
  validation_method   = "DNS"
  wait_for_validation = true
  tags = {
    Name = "${local.project}-${local.env}-backend-validation"
  }
}

data "aws_route53_zone" "main" {
  name = "codedevops.cloud." # Ensure the domain name ends with a dot

}

👉🏻data.tf

data "aws_caller_identity" "current" {}

👉🏻ecr.tf

resource "aws_ecr_repository" "foo" {
  for_each             = toset(local.ecr_names)
  name                 = each.key
  image_tag_mutability = "MUTABLE"
  tags = {
    Name = "${local.project}-${local.env}-ecr"
  }
}

👉🏻eks.tf


module "eks" {
  source                                 = "terraform-aws-modules/eks/aws"
  version                                = "20.13.1"
  cluster_name                           = local.cluster_name
  cluster_version                        = local.cluster_version
  cluster_enabled_log_types              = local.cluster_enabled_log_types
  cloudwatch_log_group_retention_in_days = 30
  cluster_endpoint_public_access         = true

  cluster_addons = {
    coredns = {
      most_recent                 = true
      resolve_conflicts_on_create = "OVERWRITE"
      configuration_values        = jsonencode(local.coredns_config)
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent              = true
      service_account_role_arn = aws_iam_role.vpc_cni.arn
    }
  }

  vpc_id     = local.vpc_id
  subnet_ids = local.public_subnet_ids
  eks_managed_node_group_defaults = {
    ## This instance type (m6a.large) is a placeholder and will not be used in the actual deployment.

  }

  eks_managed_node_groups = local.eks_managed_node_groups

  cluster_security_group_additional_rules = local.cluster_security_group_additional_rules

  enable_cluster_creator_admin_permissions = false

  access_entries = {
    for k in local.eks_access_entries : k.username => {
      kubernetes_groups = []
      principal_arn     = k.username
      policy_associations = {
        single = {
          policy_arn = k.access_policy
          access_scope = {
            type = "cluster"
          }
        }
      }
    }
  }
  tags = local.default_tags
}
#Role for vpc cni
resource "aws_iam_role" "vpc_cni" {
  name               = "${local.prefix}-vpc-cni"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "${module.eks.oidc_provider_arn}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${module.eks.oidc_provider}:sub": "system:serviceaccount:kube-system:aws-node"
        }
      }
    }
  ]
}
EOF
}
resource "aws_iam_role_policy_attachment" "vpc_cni" {
  role       = aws_iam_role.vpc_cni.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"

}

👉🏻locals.tf


data "aws_eks_cluster_auth" "eks" {
  name = module.eks.cluster_name
}

locals {
  environment                             = terraform.workspace
  k8s_info                                = lookup(var.environments, local.environment)
  cluster_name                            = lookup(local.k8s_info, "cluster_name")
  region                                  = lookup(local.k8s_info, "region")
  env                                     = lookup(local.k8s_info, "env")
  vpc_id                                  = lookup(local.k8s_info, "vpc_id")
  vpc_cidr                                = lookup(local.k8s_info, "vpc_cidr")
  public_subnet_ids                       = lookup(local.k8s_info, "public_subnet_ids")
  cluster_version                         = lookup(local.k8s_info, "cluster_version")
  cluster_enabled_log_types               = lookup(local.k8s_info, "cluster_enabled_log_types")
  eks_managed_node_groups                 = lookup(local.k8s_info, "eks_managed_node_groups")
  cluster_security_group_additional_rules = lookup(local.k8s_info, "cluster_security_group_additional_rules")
  coredns_config                          = lookup(local.k8s_info, "coredns_config")
  ecr_names                               = lookup(local.k8s_info, "ecr_names")

  prefix             = "${local.project}-${local.environment}-${var.region}"
  eks_access_entries = flatten([for k, v in local.k8s_info.eks_access_entries : [for s in v.user_arn : { username = s, access_policy = lookup(local.eks_access_policy, k), group = k }]])

  eks_access_policy = {
    viewer = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy",
    admin  = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
  }
  project    = "codedevops"
  account_id = data.aws_caller_identity.current.account_id
  default_tags = {
    environment = local.environment
    managed_by  = "terraform"
    project     = local.project
  }
}

👉🏻output.tf

output "cluster_name" {
  value       = module.eks.cluster_name
  description = "The name of the created EKS cluster."
}

output "cluster_version" {
  value       = module.eks.cluster_version
  description = "The version of Kubernetes running on the EKS cluster."
}

output "cluster_endpoint" {
  value       = module.eks.cluster_endpoint
  description = "The endpoint for the EKS Kubernetes API server."
}

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

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

output "oidc_provider_arn" {
  value = module.eks.oidc_provider_arn

}
output "acm_certificate_arn" {
  value = module.acm_backend.acm_certificate_arn

}

👉🏻provider.tf

terraform {
  backend "s3" {
    bucket = "devsecops-backend-codedevops"
    key    = "secops-dev.tfstae"
    region = "ap-south-1"
  }
}
terraform {
  required_version = ">= 0.15.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 4.29.0"
    }
    random = {
      source  = "hashicorp/random"
      version = ">= 3.6.0"
    }
    template = {
      source  = "hashicorp/template"
      version = ">= 2.2.0"
    }
  }
}
provider "aws" {
  region              = var.region
  allowed_account_ids = [434605749312]

  default_tags {
    tags = local.default_tags
  }
}
provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  token                  = data.aws_eks_cluster_auth.eks.token

}
provider "helm" {
  kubernetes {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
    token                  = data.aws_eks_cluster_auth.eks.token
  }
}

👉🏻terraform.tfvars

environments = {
  default = {
    # Global variables
    cluster_name                   = "codedevops-cluster"
    env                            = "default"
    region                         = "ap-south-1"
    vpc_id                         = "vpc-02af529e05c41b6bb"
    vpc_cidr                       = "10.0.0.0/16"
    public_subnet_ids              = ["subnet-09aeb297a112767b2", "subnet-0e25e76fb4326ce99"]
    cluster_version                = "1.29"
    cluster_endpoint_public_access = true
    ecr_names                      = ["codedevops"]

    # EKS variables
    eks_managed_node_groups = {
      generalworkload-v4 = {
        min_size       = 1
        max_size       = 1
        desired_size   = 1
        instance_types = ["m5a.xlarge"]
        capacity_type  = "SPOT"
        disk_size      = 60
        ebs_optimized  = true
        iam_role_additional_policies = {
          ssm_access        = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
          cloudwatch_access = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
          service_role_ssm  = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
          default_policy    = "arn:aws:iam::aws:policy/AmazonSSMManagedEC2InstanceDefaultPolicy"
        }
      }
    }
    cluster_security_group_additional_rules = {}

    # EKS Cluster Logging
    cluster_enabled_log_types = ["audit"]
    eks_access_entries = {
      viewer = {
        user_arn = []
      }
      admin = {
        user_arn = ["arn:aws:iam::434605749312:root"]
      }
    }
    # EKS Addons variables 
    coredns_config = {
      replicaCount = 1
    }
  }

}

👉🏻variables.tf

variable "region" {
  type        = any
  default     = "ap-south-1"
  description = "value of the region where the resources will be created"
}

variable "environments" {
  type = any

  description = "The environment configuration"
}

Step 3: Access Your EKS Cluster
Once the cluster is created, you can configure kubectl to interact with your EKS cluster using the following command:

aws eks --region update-kubeconfig --name

You can then verify the cluster connectivity:

kubectl get nodes

Troubleshooting
If you encounter any issues, refer to the Terraform documentation or raise an issue in this repository.

🏴‍☠️
source link: https://github.com/ravindrasinghh/Kubernetes-Playlist/tree/master

If you prefer a video tutorial to help guide you to create the EKS Cluster Using Terraform


This content originally appeared on DEV Community and was authored by Ravindra Singh


Print Share Comment Cite Upload Translate Updates
APA

Ravindra Singh | Sciencx (2024-08-24T12:31:44+00:00) Create an EKS Cluster Using Terraform. Retrieved from https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/

MLA
" » Create an EKS Cluster Using Terraform." Ravindra Singh | Sciencx - Saturday August 24, 2024, https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/
HARVARD
Ravindra Singh | Sciencx Saturday August 24, 2024 » Create an EKS Cluster Using Terraform., viewed ,<https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/>
VANCOUVER
Ravindra Singh | Sciencx - » Create an EKS Cluster Using Terraform. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/
CHICAGO
" » Create an EKS Cluster Using Terraform." Ravindra Singh | Sciencx - Accessed . https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/
IEEE
" » Create an EKS Cluster Using Terraform." Ravindra Singh | Sciencx [Online]. Available: https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/. [Accessed: ]
rf:citation
» Create an EKS Cluster Using Terraform | Ravindra Singh | Sciencx | https://www.scien.cx/2024/08/24/create-an-eks-cluster-using-terraform/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.