Amazon EKS (Elastic Kubernetes Service)
Managed Kubernetes control plane on AWS. AWS runs the K8s API server, scheduler, controller manager, and etcd; you bring (or let AWS bring) the worker nodes. For K8s fundamentals see backend/17_kubernetes/.
Control plane vs nodes
- Control plane — fully managed by AWS, costs $0.10/hour (~$73/month) per cluster.
- Nodes — your responsibility. Options:
- Self-managed EC2 — full control, you patch them.
- Managed Node Groups — AWS provisions EC2, you pick instance types; AWS does patching with rolling drain.
- Fargate — serverless pods, no nodes to manage. Pay per pod vCPU/RAM.
Most production clusters mix Managed Node Groups (steady workloads on Reserved/Spot instances) + Fargate (burst, low-volume).
IRSA — IAM Roles for Service Accounts
The EKS-specific feature that matters most for security: pods get IAM identities via Kubernetes ServiceAccounts, no long-lived AWS keys in the cluster.
apiVersion: v1
kind: ServiceAccount
metadata:
name: orders
namespace: prod
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/orders-pod-role
spec:
serviceAccountName: orders
containers:
- name: app
image: ...
Then in code:
import boto3
s3 = boto3.client("s3")
s3.put_object(...) # uses orders-pod-role automatically
The IAM role’s trust policy lists the cluster OIDC + the ServiceAccount; AWS SDK calls AssumeRoleWithWebIdentity using the projected token from the pod. Per-pod least-privilege without sidecars.
Successor: EKS Pod Identity (2023+) — a slightly simpler API, but IRSA is still the dominant pattern.
Karpenter — the modern autoscaler
Where you’d use Cluster Autoscaler on most K8s, EKS users prefer Karpenter:
- Provisions EC2 nodes directly from EC2 API (no Auto Scaling Groups).
- Picks instance type per pending pod, from a
NodePoolspec of allowed shapes. - Consolidates underutilized nodes automatically.
- Bin-packs aggressively — better utilization than ASG-based autoscaling.
apiVersion: karpenter.sh/v1
kind: NodePool
metadata: { name: default }
spec:
template:
spec:
requirements:
- { key: kubernetes.io/arch, operator: In, values: [amd64, arm64] }
- { key: karpenter.sh/capacity-type, operator: In, values: [on-demand, spot] }
- { key: node.kubernetes.io/instance-type, operator: In, values: [c6g.large, c6g.xlarge, m6g.large, m6g.xlarge] }
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s
Karpenter mixes spot + on-demand, ARM + x86, and consolidates as load drops. Big cost win on spiky workloads.
VPC CNI and networking
EKS uses AWS VPC CNI by default — each pod gets a real VPC IP from the same subnet as the node. Pods are first-class VPC citizens; can use VPC Security Groups directly (with the Security Groups for Pods feature).
Implication: instance type caps pod density (each instance has limited ENI/IP allocation). Use Prefix Delegation to get more pods per node.
Alternative CNIs: Cilium (eBPF), Calico (NetworkPolicy + advanced security). Most teams stay on AWS VPC CNI unless they need NetworkPolicy or eBPF features.
Load balancing
AWS Load Balancer Controller
Watches Ingress objects and Service: LoadBalancer; provisions ALBs / NLBs accordingly. Most efficient pattern:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip # bypass NodePort, direct to pod IP
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:...
spec:
rules: ...
target-type: ip registers pod IPs directly with the ALB target group (no NodePort hop). Use it.
Ingress vs Gateway API
Gateway API (k8s 1.29+ GA) is the more expressive successor. EKS supports it via the AWS Gateway API Controller. New deployments — prefer Gateway API for richer routing.
Storage
- EBS CSI driver — block storage for StatefulSets.
- EFS CSI driver — shared file system; multi-pod RWX.
- FSx CSI — high-performance.
EBS is single-AZ; pin pods to nodes in the same AZ as the volume (via topology constraints).
Cluster security: control plane + addons
- EKS Auto Mode (2024+) — AWS manages nodes + addons (Karpenter, VPC CNI, AWS Load Balancer Controller, CoreDNS, kube-proxy). Closest to “K8s without ops.”
- EKS Add-ons — managed installs of core components. Use these instead of self-hosting.
- Pod Security Standards — enforce baseline / restricted profiles via Pod Security admission.
- GuardDuty for EKS — runtime threat detection.
EKS Fargate
Pods scheduled on AWS-managed compute, no nodes you maintain.
apiVersion: eksctl.io/v1alpha5
kind: FargateProfile
metadata: { name: orders-fp }
spec:
cluster: prod
selectors:
- namespace: prod
labels: { compute: fargate }
Pods in prod namespace with label compute: fargate run on Fargate; others on EC2 nodes. Costs more per CPU/RAM than EC2 (especially Spot), but no node ops.
Mix and match: dev/CI on Fargate (no node management); steady production on Karpenter + Spot for cost.
Common gotchas
- No autoscaler in a fresh cluster. Pods Pending → no nodes added. Install Karpenter or Cluster Autoscaler explicitly.
- VPC CNI IP exhaustion at high pod density on smaller instance types. Enable Prefix Delegation.
- Cluster upgrades. Control plane is one click; node groups must be drained and replaced. Run two K8s versions side-by-side during upgrade.
- CoreDNS at scale can become a bottleneck. Scale up replicas; use NodeLocal DNSCache for high-QPS workloads.
- aws-auth ConfigMap legacy: IAM users mapped to K8s users via a single ConfigMap. Easy to break cluster auth. EKS Access Entries (newer) is the API-driven replacement.
When to pick EKS over ECS
- You already use K8s (multi-cloud, in-house tooling, hires).
- You want polyglot orchestration with a portable mental model.
- You need K8s-ecosystem operators (Argo, Flux, Crossplane, Istio, Linkerd).
- You want fine-grained network policies via Cilium / Calico.
When ECS wins:
- AWS-only shop with no K8s expertise.
- You want lower cognitive overhead.
- Steady simple workloads where K8s features go unused.
Cost notes
- Cluster fee: $73/month per EKS cluster. Don’t run 50 clusters; use namespaces.
- Nodes: Karpenter with Spot + ARM saves 50-80% vs Reserved x86 on-demand.
- Fargate: ~20% premium over EC2 equivalent; no node ops to amortize.
- NAT Gateway is the surprise bill on EKS. Use VPC Endpoints for S3/ECR; consider IPv6 to skip NAT.
Interview angle
- “EKS vs ECS — when each?” — EKS for K8s expertise / multi-cloud / rich ecosystem (Argo, Istio); ECS for AWS-native simplicity, no K8s control plane cost, simpler mental model. Both can run on Fargate.
- “What’s IRSA?” — IAM Roles for Service Accounts. K8s ServiceAccount annotated with an IAM role ARN; AWS SDK in the pod assumes that role via OIDC. Per-pod IAM least-privilege, no long-lived keys in the cluster.
- “Karpenter vs Cluster Autoscaler?” — Cluster Autoscaler scales node groups (ASGs); Karpenter provisions EC2 directly per Pending pod, picks instance type from allowed shapes, consolidates underutilized nodes automatically. Karpenter is the modern default on EKS.
- “How do you handle secrets in EKS?” — External Secrets Operator + IRSA: ESO pulls from Secrets Manager / SSM as the operator’s IAM role; materializes k8s Secrets that pods consume. Or Secrets Store CSI driver — mount secrets as files directly without etcd storage.
- “VPC CNI vs Cilium?” — VPC CNI: AWS default; pods are first-class VPC citizens with real subnet IPs. Cilium: eBPF-based; richer NetworkPolicies, host firewall, observability without sidecar. Pick Cilium for advanced network policy / observability needs.
- “EKS Fargate trade-offs?” — no node ops (great for small / bursty workloads, CI), but ~20% premium and not all features supported (no DaemonSets, no privileged pods, limited storage). Mix with EC2 nodes for steady production.