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.
GIT LINK: https://github.com/ravindrasinghh/Kubernetes-Playlist
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
terraform init
terraform plan
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