Skip to content
Amazon EKS: Managed Kubernetes on AWS

Amazon EKS: Managed Kubernetes on AWS

DodaTech Updated Jun 20, 2026 7 min read

Amazon EKS (Elastic Kubernetes Service) is a managed Kubernetes control plane that runs the upstream Kubernetes distribution — handling control plane availability, updates, and scaling so you focus on your applications.

What You’ll Learn

  • Setting up an EKS cluster with managed node groups
  • IAM roles for service accounts (IRSA) for fine-grained permissions
  • Installing ALB ingress controller for traffic routing
  • Cluster Autoscaler vs Karpenter for node scaling
  • EBS and EFS CSI drivers for persistent storage
  • Cost optimization strategies for EKS

Why EKS Matters

Running Kubernetes yourself means managing the control plane (etcd, API server, scheduler, controller manager) — which requires expertise, dedicated resources, and constant maintenance. EKS manages the control plane for you, providing automatic updates, patching, and 99.95% SLA. DodaTech runs Durga Antivirus Pro’s internal tooling on EKS — data processing jobs, CI/CD runners, and internal dashboards all run on a shared EKS cluster, with each team having their own namespaces and IAM roles.

    flowchart LR
    A[Kubernetes & AWS] --> B[Amazon EKS]
    B --> C[Control Plane]
    B --> D[Node Groups]
    B --> E[Ingress]
    B --> F[Storage]
    B --> G[Scaling]
    C --> H[Managed by AWS]
    D --> I[Managed / Self-Managed / Fargate]
    E --> J[ALB Ingress Controller]
    G --> K[Cluster Autoscaler / Karpenter]
    style B fill:#f90,color:#fff
  
Prerequisites: Strong Kubernetes fundamentals. Familiarity with AWS services (EC2, IAM, VPC). Experience with Terraform is helpful.

Cluster Setup

Terraform Configuration

# eks-cluster.tf
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"

  cluster_name    = "dodatech-prod"
  cluster_version = "1.28"

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  cluster_endpoint_public_access = false  # Private cluster only

  eks_managed_node_groups = {
    general = {
      desired_size = 3
      min_size     = 2
      max_size     = 10

      instance_types = ["m5.large", "m5a.large"]
      capacity_type  = "ON_DEMAND"
    }

    spot = {
      desired_size = 2
      min_size     = 0
      max_size     = 20

      instance_types = ["c5.2xlarge", "c5a.2xlarge"]
      capacity_type  = "SPOT"
    }
  }

  tags = {
    Environment = "production"
  }
}

data "aws_eks_cluster_auth" "this" {
  name = module.eks.cluster_name
}
# Configure kubectl
aws eks update-kubeconfig --region us-east-1 --name dodatech-prod

# Verify cluster
kubectl get nodes

# Output:
# NAME                          STATUS   ROLES    AGE   VERSION
# ip-10-0-1-101.ec2.internal    Ready    <none>   2h    v1.28.3
# ip-10-0-2-102.ec2.internal    Ready    <none>   2h    v1.28.3
# ip-10-0-3-103.ec2.internal    Ready    <none>   2h    v1.28.3

IAM Roles for Service Accounts (IRSA)

IRSA maps Kubernetes service accounts to IAM roles, giving each pod precise permissions:

# irsa.tf
module "irsa" {
  source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

  role_name  = "app-s3-access"
  attach_s3_policy = true
  s3_bucket_arns   = ["arn:aws:s3:::dodatech-app-data/*"]

  oidc_providers = {
    main = {
      provider_arn = module.eks.oidc_provider_arn
      namespace_service_accounts = ["default:app-sa"]
    }
  }
}
# app-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/app-s3-access
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  serviceAccountName: app-sa
  containers:
  - name: app
    image: dodatech/app:latest
    # This pod can now read/write to the S3 bucket

ALB Ingress Controller

Route external traffic to services:

# alb-ingress.tf
resource "helm_release" "aws_lb_controller" {
  name       = "aws-load-balancer-controller"
  repository = "https://aws.github.io/eks-charts"
  chart      = "aws-load-balancer-controller"
  namespace  = "kube-system"

  set {
    name  = "clusterName"
    value = module.eks.cluster_name
  }
}
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dodatech-api
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:123456789012:certificate/abc123
spec:
  rules:
  - host: api.dodatech.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Scaling: Cluster Autoscaler vs Karpenter

Cluster Autoscaler

Scales node groups based on unschedulable pods:

# cluster-autoscaler-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-autoscaler-status
  namespace: kube-system
data:
  # Autoscaler will scale between min and max set in node group
  # Works with ASGs — limited to instance types in the ASG
---
# Requires IAM permissions to modify ASG desired counts

Karpenter

Karpenter is a newer, more flexible autoscaler that provisions instances directly:

# karpenter-provisioner.yaml
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  requirements:
    - key: karpenter.sh/capacity-type
      operator: In
      values: ["on-demand", "spot"]
    - key: kubernetes.io/arch
      operator: In
      values: ["amd64", "arm64"]
    - key: node.kubernetes.io/instance-type
      operator: In
      values:
        - m5.large
        - m5.xlarge
        - c5.2xlarge
  limits:
    resources:
      cpu: 1000
  provider:
    subnetSelector:
      kubernetes.io/cluster/dodatech-prod: owned
    securityGroupSelector:
      kubernetes.io/cluster/dodatech-prod: owned
  ttlSecondsAfterEmpty: 30

Why Karpenter wins: Provisions instances in seconds (vs minutes for ASGs), supports spot and on-demand together, and manages multiple instance types without creating multiple node groups.

Storage with CSI Drivers

# ebs-storage.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp3
  resources:
    requests:
      storage: 100Gi
---
# After installing aws-ebs-csi-driver via Helm
# Pods can mount EBS volumes for persistent storage
# efs-storage.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-claim
spec:
  accessModes:
    - ReadWriteMany  # Multiple pods can read/write simultaneously
  storageClassName: efs-sc
  resources:
    requests:
      storage: 100Gi  # EFS is elastic — this is a placeholder

Cost Optimization

StrategySavingsNotes
Spot instances60-90%Use spot for batch, stateless, and non-critical workloads
Karpenter20-40%Better packing, multi-instance-type selection
Fargate for control planeFixed costNo node management for system pods
Graviton (ARM)20-40%Better perf/cost ratio for most workloads
Cluster rightsizing30-50%Use AWS Compute Optimizer recommendations

Common Mistakes

  1. Publicly accessible cluster endpoint: Exposing the Kubernetes API server to the internet is a security risk. Set cluster_endpoint_public_access = false and use VPN or Direct Connect for access.

  2. Not using IRSA: Giving nodes broad IAM permissions means any pod can access any AWS resource. Use IRSA to give each pod exactly the permissions it needs.

  3. Over-provisioning node groups: Multiple large node groups with fixed instance types waste money. Use Karpenter with diverse instance types for better packing and cost.

  4. No pod resource requests/limits: Without resource requests, the scheduler can’t make informed decisions. Without limits, a runaway pod can starve other pods. Always set both.

  5. Ignoring cluster autoscaling: Without autoscaling, you either over-provision (waste money) or under-provision (outages). Always configure at least one autoscaler.

Practice Questions

  1. What is the difference between EKS and self-managed Kubernetes? Answer: EKS manages the control plane (API server, etcd) — AWS handles updates, patching, and HA. Self-managed requires you to run and maintain the control plane on your own infrastructure.

  2. What is IRSA and why is it important? Answer: IAM Roles for Service Accounts maps Kubernetes service accounts to IAM roles. It gives each pod fine-grained AWS permissions without sharing node-level credentials.

  3. How does Karpenter differ from Cluster Autoscaler? Answer: Cluster Autoscaler works with ASGs and takes minutes to provision nodes. Karpenter provisions instances directly in seconds, supports multiple instance types, and handles spot/on-demand together.

  4. When would you use EFS vs EBS for persistent storage? Answer: EBS for single-pod storage (databases) — ReadWriteOnce, low latency. EFS for multi-pod storage (shared configs, logs) — ReadWriteMany, higher latency.

Challenge

Deploy a production EKS cluster: create an EKS cluster with Terraform (private endpoint, managed node groups, IRSA), install ALB ingress controller, deploy a sample API with autoscaling, configure Karpenter for node provisioning, set up EBS CSI driver for database storage, implement spot instances for non-critical workloads, and configure CloudWatch Container Insights for monitoring.

FAQ

How much does EKS cost?
: EKS charges $0.10 per hour per cluster ($73/month) for the control plane. Node costs are additional (EC2 or Fargate). You pay for what you run.
Can I use EKS with Fargate?
: Yes. EKS Fargate runs pods without managing nodes. Good for system pods and variable workloads. More expensive than EC2 for steady-state workloads.
How do EKS updates work?
: AWS manages control plane updates. For node groups, you create new node groups with the updated AMI and migrate workloads. EKS supports three Kubernetes minor versions at a time.
What is the difference between EKS and ECS?
: ECS is AWS-specific, simpler, and deeply integrated with AWS services. EKS is standard Kubernetes — portable across clouds, larger ecosystem, but more complex.
How do I expose an EKS service to the internet?
: Use the AWS Load Balancer Controller for ALB/NLB integration, or an Ingress resource with the ALB ingress controller. Avoid NodePort and LoadBalancer services directly.

Mini Project: EKS Status Checker

#!/bin/bash
# eks-status.sh
CLUSTER="dodatech-prod"
REGION="us-east-1"

echo "=== EKS Cluster Status ==="
aws eks describe-cluster --name $CLUSTER --region $REGION \
  --query '{Status: cluster.status, Version: cluster.version, Endpoint: cluster.endpoint, Created: cluster.createdAt}'

echo -e "\n=== Node Groups ==="
aws eks list-nodegroups --cluster-name $CLUSTER --region $REGION \
  --query 'nodegroups' --output yaml

echo -e "\n=== Nodes ==="
kubectl get nodes -o wide

echo -e "\n=== System Pods ==="
kubectl get pods -n kube-system

echo -e "\n=== Resource Usage ==="
kubectl top nodes

What’s Next

TopicDescription
Serverless Framework
Build and deploy serverless apps
AWS ECS
Running containers at scale

Related topics: Kubernetes, AWS, Terraform, EKS

What’s Next

Congratulations on completing this EKS tutorial! Here’s where to go from here:

  • Practice daily — Deploy an app on EKS with a CI/CD pipeline
  • Build a project — Set up Karpenter with spot and on-demand nodes
  • Explore related topics — Check out the Serverless Framework

Remember: every expert was once a beginner. Keep coding!

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro