Kubernetes on AWS EKS — Complete Setup Guide 2026
Advertisement
Introduction
Why This Matters
AWS Elastic Kubernetes Service (EKS) is the most widely used managed Kubernetes platform in 2026. It offloads the control plane — API server, etcd, scheduler, and controller manager — to AWS, letting your team focus on workloads instead of cluster infrastructure. EKS integrates natively with IAM, VPC, ALB, ECR, CloudWatch, and Secrets Manager, making it the natural choice for teams already on AWS.
This guide walks through creating a production-ready EKS cluster from scratch using eksctl and the AWS CLI.
Prerequisites and Tooling
Install the required CLI tools before starting:
# Install AWS CLI v2
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install
# Configure AWS credentials
aws configure
# Enter: Access Key ID, Secret Access Key, region (us-east-1), output format (json)
# Install eksctl (the official EKS CLI)
curl --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_Linux_amd64.tar.gz" | tar xz
sudo mv eksctl /usr/local/bin
# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Verify installations
aws --version
eksctl version
kubectl version --clientCreating an EKS Cluster With eksctl
The fastest way to create a production-ready cluster is with an eksctl config file:
# cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-production-cluster
region: us-east-1
version: "1.29"
vpc:
cidr: "10.0.0.0/16"
nat:
gateway: HighlyAvailable # NAT gateway per AZ
managedNodeGroups:
- name: ng-general
instanceType: t3.medium
minSize: 2
maxSize: 10
desiredCapacity: 3
volumeSize: 50
privateNetworking: true
labels:
role: worker
tags:
Environment: production
iam:
withAddonPolicies:
imageBuilder: true
autoScaler: true
albIngress: true
cloudWatch: true
addons:
- name: vpc-cni
version: latest
- name: coredns
version: latest
- name: kube-proxy
version: latest
- name: aws-ebs-csi-driver
version: latest
wellKnownPolicies:
ebsCSIController: true
cloudWatch:
clusterLogging:
enableTypes: ["api", "audit", "authenticator", "controllerManager", "scheduler"]# Create the cluster (takes ~15 minutes)
eksctl create cluster -f cluster.yaml
# Update kubeconfig to connect kubectl to the new cluster
aws eks update-kubeconfig --name my-production-cluster --region us-east-1
# Verify nodes are ready
kubectl get nodes -o wideIAM Roles for Service Accounts (IRSA)
IRSA is the AWS-native way to give Kubernetes pods fine-grained AWS permissions without sharing node-level IAM roles.
# Enable OIDC provider for the cluster
eksctl utils associate-iam-oidc-provider \
--cluster my-production-cluster \
--region us-east-1 \
--approve
# Create a service account with an S3 read policy
eksctl create iamserviceaccount \
--cluster my-production-cluster \
--namespace my-app \
--name s3-reader \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--approve
# Use the service account in a PodapiVersion: v1
kind: Pod
metadata:
name: my-app
namespace: my-app
spec:
serviceAccountName: s3-reader
containers:
- name: app
image: my-app:latest
# AWS SDK automatically picks up credentials via projected tokenAWS Load Balancer Controller
The AWS Load Balancer Controller provisions Application Load Balancers (ALB) for Kubernetes Ingress resources.
# Add EKS Helm repo
helm repo add eks https://aws.github.io/eks-charts
helm repo update
# Install the controller
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=my-production-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controllerSample Ingress that provisions an ALB:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: my-app
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:123456789:certificate/abc
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80Cluster Autoscaler
The Cluster Autoscaler adds or removes EC2 nodes based on pending pods.
helm repo add autoscaler https://kubernetes.github.io/autoscaler
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
--namespace kube-system \
--set autoDiscovery.clusterName=my-production-cluster \
--set awsRegion=us-east-1 \
--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789:role/cluster-autoscalerUseful EKS Operations
# List all EKS clusters in a region
aws eks list-clusters --region us-east-1
# Describe a cluster
aws eks describe-cluster --name my-production-cluster --region us-east-1
# Update cluster Kubernetes version
eksctl upgrade cluster --name my-production-cluster --region us-east-1 --approve
# Add a new managed node group
eksctl create nodegroup \
--cluster my-production-cluster \
--name ng-spot \
--spot \
--instance-types t3.medium,t3.large \
--nodes-min 1 \
--nodes-max 5
# Delete the cluster (removes all resources)
eksctl delete cluster --name my-production-cluster --region us-east-1Common Mistakes
- Using the default VPC — always create a dedicated VPC with private subnets for worker nodes; the default VPC puts everything on public subnets.
- Not enabling IRSA — using node-level IAM roles grants all pods on a node the same AWS permissions; IRSA provides pod-level isolation.
- Skipping control plane logs — enable API, audit, and authenticator logs to CloudWatch; without them, debugging auth issues is nearly impossible.
- Under-provisioning node groups — set
minSizeandmaxSizecorrectly and enable the Cluster Autoscaler from day one; manual scaling causes outages. - Not tagging subnets — EKS requires specific tags on subnets for the load balancer controller and Cluster Autoscaler to discover them automatically.
Best Practices
- Use managed node groups — they handle node draining, OS patching, and rolling updates automatically.
- Enable spot instances for non-critical workloads — mix on-demand and spot instance types in node groups to reduce cost by 60-80%.
- Use private endpoints — set cluster endpoint access to private-only and use VPN or AWS Systems Manager for
kubectlaccess. - Rotate node groups on version upgrades — create a new node group with the updated AMI and drain the old one instead of in-place upgrades.
- Implement Pod Disruption Budgets — ensure rolling updates and autoscaler operations don't take down all replicas of a service simultaneously.
Key Takeaways
- AWS EKS manages the Kubernetes control plane (API server, etcd, scheduler) on your behalf; you only manage worker node groups.
- Use
eksctlwith a declarative YAML config file for reproducible, version-controlled cluster creation. - IRSA (IAM Roles for Service Accounts) provides pod-level AWS permissions using OIDC federation — safer than node-level IAM roles.
- The AWS Load Balancer Controller provisions ALBs from Kubernetes Ingress resources using annotations.
- The Cluster Autoscaler automatically adjusts node group size based on pending pod resource requests.
- EKS managed node groups handle OS patching and node replacement automatically, reducing operational burden.
- Always use private subnets for worker nodes and enable control plane logging to CloudWatch from cluster creation.
- Subnet tagging (
kubernetes.io/role/internal-elbandkubernetes.io/cluster/name) is required for AWS add-ons to discover VPC resources.
Advertisement