Skip to main content

EKS - Elastic Kubernetes Service

What is EKS?

Amazon EKS is a managed Kubernetes service that makes it easy to run Kubernetes on AWS without needing to install and operate your own Kubernetes control plane.

Key Features

  • Managed Control Plane - AWS manages Kubernetes masters
  • Highly Available - Control plane across multiple AZs
  • Secure - IAM integration, VPC isolation
  • Scalable - Supports thousands of pods
  • Compatible - Standard Kubernetes, works with existing tools

EKS Architecture

┌──────────────────────────────────────────┐
│ AWS Managed │
│ ┌──────────────────────────┐ │
│ │ Kubernetes │ │
│ │ Control Plane │ │
│ │ (Masters, etcd, API) │ │
│ └───────────┬──────────────┘ │
└───────────────┼──────────────────────────┘
│ Kubernetes API
┌───────────────▼──────────────────────────┐
│ Your AWS Account │
│ ┌──────────────────────────────┐ │
│ │ EKS Node Group │ │
│ │ (Worker Nodes) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │Pod │ │Pod │ │Pod │ │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ │ (EC2 or Fargate) │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────┘

Creating an EKS Cluster

Prerequisites:

# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# Install eksctl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin

# Install AWS CLI
pip install awscli --upgrade

Using eksctl (Easiest):

# Create cluster (takes ~15 minutes)
eksctl create cluster \
--name my-cluster \
--region us-east-1 \
--nodegroup-name standard-workers \
--node-type t3.medium \
--nodes 3 \
--nodes-min 1 \
--nodes-max 4 \
--managed

# Update kubeconfig
aws eks update-kubeconfig \
--region us-east-1 \
--name my-cluster

# Verify connection
kubectl get nodes

# Delete cluster
eksctl delete cluster --name my-cluster

Using CloudFormation:

AWSTemplateFormatVersion: '2010-09-09'
Description: 'EKS Cluster'

Resources:
EKSClusterRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: eks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEKSClusterPolicy

EKSCluster:
Type: AWS::EKS::Cluster
Properties:
Name: my-cluster
Version: '1.27'
RoleArn: !GetAtt EKSClusterRole.Arn
ResourcesVpcConfig:
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
SecurityGroupIds:
- !Ref ClusterSecurityGroup

NodeInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

NodeGroup:
Type: AWS::EKS::Nodegroup
DependsOn: EKSCluster
Properties:
ClusterName: !Ref EKSCluster
NodegroupName: standard-workers
NodeRole: !GetAtt NodeInstanceRole.Arn
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
ScalingConfig:
DesiredSize: 3
MinSize: 1
MaxSize: 4
InstanceTypes:
- t3.medium

Outputs:
ClusterName:
Value: !Ref EKSCluster
ClusterEndpoint:
Value: !GetAtt EKSCluster.Endpoint

Deploying Applications to EKS

1. Create Deployment:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

2. Create Service:

# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080

3. Deploy:

# Apply manifests
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# Check status
kubectl get deployments
kubectl get pods
kubectl get services

# Get load balancer URL
kubectl get service my-app-service

EKS with Application Load Balancer

Install AWS Load Balancer Controller:

# Create IAM policy
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json

aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json

# Create service account
eksctl create iamserviceaccount \
--cluster=my-cluster \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::123456789012:policy/AWSLoadBalancerControllerIAMPolicy \
--approve

# Install controller using Helm
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=my-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller

Create Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80

EKS Best Practices

1. Use IAM Roles for Service Accounts (IRSA)

apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/MyAppRole
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
serviceAccountName: my-app-sa
containers:
- name: my-app
image: my-app:latest

2. Enable Pod Security Policies

3. Use Cluster Autoscaler

# Install cluster autoscaler
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml

# Edit deployment to add cluster name
kubectl -n kube-system edit deployment.apps/cluster-autoscaler

4. Implement Network Policies

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {}
policyTypes:
- Ingress

5. Use Managed Node Groups

  • Automatic updates
  • Easy scaling
  • Better integration

Monitoring EKS

Install Metrics Server:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# View metrics
kubectl top nodes
kubectl top pods

Container Insights:

# Install CloudWatch Container Insights
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/my-cluster/;s/{{region_name}}/us-east-1/" | kubectl apply -f -

Run production-grade Kubernetes clusters on AWS with EKS for container orchestration at scale!