Amazon EKS: Managed Kubernetes on AWS Without the Control Plane Work
Kubernetes has become the standard for running containerised workloads at scale. The problem is that operating a production Kubernetes cluster — maintaining etcd, the API server, the scheduler, and controller manager across three control plane nodes — is a full-time job. Amazon EKS removes that burden by managing the control plane for you.
With EKS, AWS runs the Kubernetes control plane components in a multi-AZ configuration, handles control plane upgrades, patches the OS, and backs up etcd automatically. You focus on deploying workloads.
EKS Architecture
┌──────────────────────────────────────────────────────────────────┐│ EKS Cluster Architecture ││ ││ AWS-Managed Control Plane (invisible to you) ││ ┌──────────────────────────────────────────────────────────┐ ││ │ Kubernetes API Server │ etcd │ Scheduler │ Controllers │ ││ │ HA across 3 AZs — AWS manages this entirely │ ││ └──────────────────────────────────────────────────────────┘ ││ │ ││ Your VPC │ kubectl / AWS SDK ││ ┌────────────────────────┴──────────────────────────────┐ ││ │ Worker Nodes (EC2 Managed Node Group) │ ││ │ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │ ││ │ │ Node (AZ1) │ │ Node (AZ2) │ │ Node(AZ3) │ │ ││ │ │ Pod Pod │ │ Pod Pod │ │ Pod Pod │ │ ││ │ └──────────────┘ └──────────────┘ └────────────┘ │ ││ └───────────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────────────┘Creating an EKS Cluster
The easiest way to create an EKS cluster is with eksctl, the official CLI:
# Install eksctlbrew install eksctl # macOS# or download from github.com/eksctl-io/eksctl
# Create cluster with a managed node groupeksctl create cluster \ --name production \ --region us-east-1 \ --version 1.29 \ --nodegroup-name general-workers \ --instance-types m6i.large \ --nodes 3 \ --nodes-min 2 \ --nodes-max 10 \ --managedThis creates the control plane, a VPC, subnets, security groups, and a managed node group. It takes about 15 minutes.
Alternatively, with the AWS CLI:
aws eks create-cluster \ --name production \ --kubernetes-version 1.29 \ --role-arn arn:aws:iam::123456789012:role/EKSClusterRole \ --resources-vpc-config \ subnetIds=subnet-0a1b2c,subnet-0d4e5f,subnet-0g6h7i,\ securityGroupIds=sg-eks-control-plane,\ endpointPublicAccess=true,\ endpointPrivateAccess=trueAfter the cluster is ready, configure kubectl:
aws eks update-kubeconfig \ --region us-east-1 \ --name productionManaged Node Groups
Managed node groups are EC2 Auto Scaling Groups where AWS handles node provisioning, OS updates, and Kubernetes version upgrades. The nodes use an EKS-optimised Amazon Linux 2 or Bottlerocket AMI.
aws eks create-nodegroup \ --cluster-name production \ --nodegroup-name api-workers \ --scaling-config minSize=2,maxSize=10,desiredSize=3 \ --instance-types m6i.large m6i.xlarge \ --subnets subnet-0a1b2c subnet-0d4e5f subnet-0g6h7i \ --ami-type AL2_x86_64 \ --node-role arn:aws:iam::123456789012:role/EKSNodeRole \ --labels tier=api \ --taints key=dedicated,value=api,effect=NO_SCHEDULEThe --taints flag marks nodes so only pods that tolerate the taint are scheduled there. Combined with node selectors, this lets you dedicate specific nodes to specific workloads.
EKS with Fargate
For fully serverless Kubernetes, EKS Fargate profiles let pods run without managing EC2 nodes. You define namespace and label selectors; matching pods run on Fargate.
aws eks create-fargate-profile \ --cluster-name production \ --fargate-profile-name api-namespace \ --pod-execution-role-arn arn:aws:iam::123456789012:role/EKSFargatePodRole \ --subnets subnet-private-0a1b2c subnet-private-0d4e5f \ --selectors '[ {"namespace": "api", "labels": {"workload": "serverless"}}, {"namespace": "default"} ]'Pods in the api namespace with label workload: serverless, and all pods in the default namespace, run on Fargate.
Fargate pods each run in their own isolated compute environment. There are no shared nodes to worry about. The tradeoff: DaemonSets do not run on Fargate (no access to the node), persistent volumes need EFS rather than EBS, and pod startup is slower.
VPC CNI and Networking
EKS uses the AWS VPC CNI plugin by default. Each pod gets a real VPC IP address from one of the node’s ENI secondary IP addresses.
Node 10.0.1.50 (m6i.large, can have ~27 secondary IPs): ENI 1 (primary): Node IP: 10.0.1.50 Pod IPs: 10.0.1.60, 10.0.1.61, 10.0.1.62 ... ENI 2 (secondary): Pod IPs: 10.0.1.80, 10.0.1.81, 10.0.1.82 ...Because pods have VPC IPs, they can communicate directly with other AWS resources (RDS, Lambda, other EC2) without NAT. Security groups on pods allow fine-grained network access control at the pod level (Security Groups for Pods feature).
For clusters with many pods, the default VPC CIDR may not have enough IP space. Consider enabling custom networking or IPv6 for large clusters.
Managed Add-Ons
EKS manages several critical add-ons with version lifecycle tied to Kubernetes versions:
# List available add-onsaws eks describe-addon-versions --kubernetes-version 1.29
# Install CoreDNSaws eks create-addon \ --cluster-name production \ --addon-name coredns \ --addon-version v1.11.1-eksbuild.4
# Install EBS CSI driver (required for PersistentVolumes backed by EBS)aws eks create-addon \ --cluster-name production \ --addon-name aws-ebs-csi-driver \ --service-account-role-arn arn:aws:iam::123456789012:role/EBSCSIRoleCommon managed add-ons:
- CoreDNS: cluster DNS resolution
- kube-proxy: network rules on each node
- VPC CNI: pod networking
- EBS CSI Driver: persistent volumes backed by EBS
- EFS CSI Driver: persistent volumes backed by EFS (multi-AZ, multi-pod)
IAM for Service Accounts (IRSA)
In Kubernetes, pods need AWS permissions to call services like S3 or DynamoDB. IRSA lets you bind an IAM role to a Kubernetes service account using OIDC federation — no need for instance profiles or long-lived credentials on nodes.
# Enable OIDC provider for the clustereksctl utils associate-iam-oidc-provider \ --cluster production \ --approve
# Create IAM role for the service accounteksctl create iamserviceaccount \ --cluster production \ --namespace api \ --name api-service-account \ --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \ --approveIn your deployment:
apiVersion: apps/v1kind: Deploymentmetadata: name: api namespace: apispec: template: spec: serviceAccountName: api-service-account containers: - name: api image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/api:v1The pod’s service account token is automatically projected and the SDK uses it to assume the IAM role. No credentials to manage.
Deploying an Application
apiVersion: apps/v1kind: Deploymentmetadata: name: web-api namespace: productionspec: replicas: 3 selector: matchLabels: app: web-api template: metadata: labels: app: web-api spec: containers: - name: api image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-api:v2.1 ports: - containerPort: 8080 resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 5---apiVersion: v1kind: Servicemetadata: name: web-api-svc namespace: production annotations: service.beta.kubernetes.io/aws-load-balancer-type: "external" service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"spec: type: LoadBalancer selector: app: web-api ports: - port: 80 targetPort: 8080kubectl apply -f deployment.yamlkubectl rollout status deployment/web-api -n productionThe AWS Load Balancer Controller (installed separately) reads the annotation and provisions an NLB pointing to the pod IPs.
Cluster Autoscaler vs Karpenter
Cluster Autoscaler adjusts the number of nodes in your node groups based on unscheduled pods and underutilised nodes. It is the traditional approach and works well with managed node groups.
Karpenter (AWS-developed, open source) is the modern alternative. Instead of scaling node groups, Karpenter provisions individual nodes on demand when pods cannot be scheduled. It selects the optimal instance type for each batch of unscheduled pods, supports Spot Instances natively, and consolidates underutilised nodes aggressively. For new EKS clusters, Karpenter is the recommended autoscaler.
Common Interview Questions
Q: What does EKS manage vs what do you manage? AWS manages: Kubernetes API server, etcd, scheduler, controller manager, control plane HA across AZs, control plane OS patches, control plane Kubernetes upgrades. You manage: worker node OS updates (or delegate to managed node groups), Kubernetes application deployments, network policy, add-on versions.
Q: What is the difference between a managed node group and a self-managed node group? Managed node groups are EC2 ASGs where AWS manages the AMI, OS patching, and node-level Kubernetes upgrades (with controlled drain and replacement). Self-managed node groups require you to handle all of this manually. Use managed node groups unless you have a specific customisation requirement.
Q: How does IRSA work?
EKS exposes an OIDC identity provider. A Kubernetes service account has an annotation linking it to an IAM role that trusts the OIDC provider. When a pod uses that service account, a projected token is mounted. The AWS SDK exchanges that token with STS for temporary IAM credentials via the AssumeRoleWithWebIdentity API.
Q: Can EKS pods use EBS volumes?
Yes, with the EBS CSI driver add-on. Create a PersistentVolumeClaim with the gp3 StorageClass; EKS provisions an EBS volume and attaches it to the node where the pod is scheduled. Note that EBS volumes are AZ-specific, so the pod must be scheduled in the same AZ as the volume.