Crisp answer: Managed node groups are EC2 Auto Scaling Groups that EKS owns and operates. AWS handles node provisioning, OS patching, and the drain-and-terminate workflow during upgrades. You configure the instance type, size, labels, and taints.
Managed vs self-managed vs Fargate:
Managed node groups:
- AWS manages the ASG, launch template, and node lifecycle
- AWS handles graceful drain on termination
- Supports spot instances and multiple instance types
- Cannot customise the bootstrap script beyond limited options
- Best for: most workloads
Self-managed node groups:
- You manage the ASG, launch template, and AMI updates
- Full control over bootstrap, custom AMIs, Windows nodes
- More operational burden
- Best for: custom OS requirements, Windows, or GPU workloads with
specific driver needs
Fargate profiles:
- No nodes to manage at all
- Each pod runs in its own micro-VM (Firecracker)
- No DaemonSets (no node to run them on)
- No privileged containers
- Cannot use EBS volumes (only EFS)
- Best for: burst workloads, compliance (workload isolation), simplicity
Creating a managed node group:
resource "aws_eks_node_group" "workers" {
cluster_name = aws_eks_cluster.main.name
node_group_name = "workers"
node_role_arn = aws_iam_role.node.arn
subnet_ids = module.networking.private_subnet_ids
instance_types = ["m5.large", "m5.xlarge"] # multiple types for spot diversity
scaling_config {
desired_size = 3
min_size = 2
max_size = 10
}
update_config {
max_unavailable_percentage = 25 # max % of nodes unavailable during update
}
launch_template {
id = aws_launch_template.workers.id
version = aws_launch_template.workers.latest_version
}
labels = {
role = "worker"
team = "platform"
}
taint {
key = "dedicated"
value = "gpu"
effect = "NO_SCHEDULE"
}
tags = local.common_tags
depends_on = [
aws_iam_role_policy_attachment.worker_node,
aws_iam_role_policy_attachment.cni,
aws_iam_role_policy_attachment.ecr_read,
]
}
Spot instances with managed node groups:
resource "aws_eks_node_group" "spot_workers" {
capacity_type = "SPOT"
instance_types = ["m5.large", "m5.xlarge", "m4.large", "m4.xlarge"]
# Multiple instance types = better spot availability and fewer interruptions
}
Node labels and taints for workload placement:
# Schedule only monitoring pods on the monitoring node group
# Node taint:
taint:
key: dedicated
value: monitoring
effect: NoSchedule
# Pod toleration:
tolerations:
- key: dedicated
value: monitoring
effect: NoSchedule
# Combined with nodeAffinity for hard placement:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values: ["monitoring"]
What to say in the interview:
"Managed node groups are the right default for EKS. AWS handles the node lifecycle: provisioning, OS patching, and the graceful drain-and-terminate during upgrades. You give up some customisation but gain significantly less operational burden. I use multiple instance types in a node group for spot instances so that if one type is unavailable AWS tries another. For workloads that need isolation I add taints to the node group and tolerations to the pods — that guarantees certain workloads only land on dedicated nodes."