Amazon EKS — Node Management Hands-On Lab
In this lab, you’ll create different types of node groups, explore Fargate profiles, and observe how pod scheduling works with labels and taints.
Lab Objectives
- Create a managed node group with On-Demand instances
- Add a Spot node group alongside it
- Create a Fargate profile for a specific namespace
- Schedule workloads on specific node types using labels and tolerations
- Clean up all resources
Prerequisites
Ensure you have a running EKS cluster. If not, create one:
eksctl create cluster \
--name node-lab \
--region us-east-1 \
--version 1.29 \
--without-nodegroup
Step 1 — Create an On-Demand Node Group
eksctl create nodegroup \
--cluster node-lab \
--name on-demand-nodes \
--node-type t3.medium \
--nodes 2 \
--nodes-min 1 \
--nodes-max 4 \
--managed \
--node-labels "capacity-type=on-demand"
Wait for the node group to become Active:
aws eks describe-nodegroup \
--cluster-name node-lab \
--nodegroup-name on-demand-nodes \
--query 'nodegroup.status'
Verify nodes:
kubectl get nodes --show-labels | grep capacity-type
Step 2 — Add a Spot Node Group
eksctl create nodegroup \
--cluster node-lab \
--name spot-nodes \
--instance-types t3.medium,t3.large,t3a.medium,t3a.large \
--spot \
--nodes 2 \
--nodes-min 0 \
--nodes-max 6 \
--managed \
--node-labels "capacity-type=spot"
Once active, view all nodes:
kubectl get nodes -L capacity-type
Expected output:
NAME STATUS ROLES CAPACITY-TYPE
ip-10-0-1-100.ec2.internal Ready <none> on-demand
ip-10-0-2-200.ec2.internal Ready <none> on-demand
ip-10-0-1-150.ec2.internal Ready <none> spot
ip-10-0-2-250.ec2.internal Ready <none> spot
Step 3 — Schedule Workloads by Node Type
Deploy on On-Demand Nodes
# save as on-demand-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: critical-app
spec:
replicas: 2
selector:
matchLabels:
app: critical
template:
metadata:
labels:
app: critical
spec:
nodeSelector:
capacity-type: on-demand
containers:
- name: nginx
image: nginx:alpine
resources:
requests:
cpu: "100m"
memory: "128Mi"
kubectl apply -f on-demand-app.yaml
kubectl get pods -o wide -l app=critical
Verify pods are on On-Demand nodes.
Deploy on Spot Nodes
# save as spot-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-worker
spec:
replicas: 3
selector:
matchLabels:
app: batch
template:
metadata:
labels:
app: batch
spec:
nodeSelector:
capacity-type: spot
containers:
- name: worker
image: busybox
command: ["sleep", "3600"]
resources:
requests:
cpu: "100m"
memory: "64Mi"
kubectl apply -f spot-app.yaml
kubectl get pods -o wide -l app=batch
Step 4 — Create a Fargate Profile
# Create Fargate profile for the 'serverless' namespace
eksctl create fargateprofile \
--cluster node-lab \
--name serverless-profile \
--namespace serverless
# Create the namespace
kubectl create namespace serverless
# Deploy a pod
kubectl run fargate-pod --image=nginx --namespace=serverless
# Wait for it to start (Fargate cold start takes 30-60 seconds)
kubectl wait --for=condition=Ready pod/fargate-pod -n serverless --timeout=120s
Verify it’s running on Fargate:
kubectl get pod fargate-pod -n serverless -o jsonpath='{.spec.nodeName}'
# Output will be a Fargate virtual node: fargate-ip-10-0-x-x.ec2.internal
Step 5 — Observe Resource Usage
# Check node resource allocation
kubectl describe nodes | grep -A 5 "Allocated resources"
# Check Fargate pod resources
kubectl describe pod fargate-pod -n serverless | grep -A 10 "Resources"
Step 6 — Clean Up
# Delete workloads
kubectl delete deployment critical-app batch-worker
kubectl delete pod fargate-pod -n serverless
kubectl delete namespace serverless
# Delete Fargate profile
eksctl delete fargateprofile --cluster node-lab --name serverless-profile
# Delete node groups
eksctl delete nodegroup --cluster node-lab --name spot-nodes
eksctl delete nodegroup --cluster node-lab --name on-demand-nodes
# Delete cluster
eksctl delete cluster --name node-lab
What You Learned
- How to create On-Demand and Spot managed node groups side by side
- Using
nodeSelectorto schedule pods on specific node types - How Fargate profiles match pods by namespace
- The cold start delay with Fargate (~30-60 seconds)
- Different node types appear with custom labels in
kubectl get nodes