Amazon EKS — Node Management Hands-On Lab

2 minute read

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 nodeSelector to 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

Updated: