EKS Managed Node Groups Explained: How They Work, When to Use Them, and Best Practices
Amazon EKS managed node groups let AWS handle the machinery of running EC2 worker nodes: provisioning them, registering them with your cluster, and replacing them gracefully when you trigger an update. Instead of writing bootstrap scripts and drain-and-replace automation yourself, you define what you want and AWS sets up the underlying infrastructure.
The payoff is real, but it is not total automation. You still choose instance types, set scaling boundaries, decide when updates happen, and stay responsible for your workloads. Managed node groups remove the plumbing work. They do not remove the need to understand what is running on your nodes.
- What a managed node group is and how it differs from the EKS control plane
- Exactly what AWS manages for you vs what you still own
- How the update lifecycle works: AMI refreshes, Kubernetes version changes, and node draining
- When to use managed node groups vs Fargate or self-managed nodes
- Autoscaling, Spot instances, and common operational mistakes
What EKS managed node groups are#
An EKS cluster has two distinct layers: a control plane and worker nodes.
The control plane (the Kubernetes API server, scheduler, etcd, and controller manager) runs in AWS-managed infrastructure. You never provision or patch it. AWS operates it entirely on your behalf. See the Amazon EKS Overview for how the control plane fits into the full EKS architecture.
The worker nodes are EC2 instances that run in your account, in your VPC. Each node runs the kubelet agent, the containerd container runtime, and the VPC CNI plugin. When a pod is scheduled, Kubernetes picks a node, and kubelet on that node pulls the container image and starts the pod. Your application workloads live here.
A managed node group is a named collection of EC2 worker nodes managed through EKS abstractions. AWS creates an Auto Scaling Group, configures a launch template, runs the bootstrap process that registers each instance with the cluster, and exposes the group through the EKS API. You interact with the node group as a single logical object, not with individual instances or Auto Scaling Group settings directly.
The control plane is truly locked down by AWS. You cannot SSH into it, patch it, or configure it directly. The worker nodes are different: they are EC2 instances running in your AWS account, and you are responsible for their shape, security posture, and update schedule. “Managed” means the orchestration is handled for you, not that AWS owns the machines.
For a side-by-side comparison of all three EKS compute options (managed node groups, self-managed nodes, Fargate), see EKS Node Groups Explained.
Simple explanation#
A managed node group is a managed pool of EC2 worker nodes for your EKS cluster. Each node is a regular EC2 instance running in your AWS account, in your VPC, on your subnets. AWS creates the underlying Auto Scaling Group and configures the bootstrap process to register each node automatically. When you trigger an update, AWS handles the rolling replacement so you do not have to script it yourself.
The word “managed” describes the orchestration layer, not ownership. Your workloads run on EC2 instances that appear in your account and generate charges on your bill.
Analogy
Think of managed node groups like hiring through a staffing agency that handles recruiting, onboarding paperwork, and exit processes. You still decide how many people you need, what roles they fill, and what work they do. The agency removes the administrative overhead of the hiring lifecycle. The workers still work for you.
What AWS manages vs what you still manage#
This is the most important thing to understand about managed node groups. The split is clear, but it surprises a lot of people who expect more to be handled automatically.
What AWS manages:
- Provisioning the underlying EC2 Auto Scaling Group and launch template
- Bootstrapping each node so it registers with your EKS cluster
- The rolling node replacement workflow when you trigger an update
- Managed lifecycle hooks that cordon and drain nodes before termination
- EKS console and API visibility: node group status, version, and health
- Discovery integration so the Cluster Autoscaler can find and scale the group
- Optional node auto repair: automatic detection and replacement of degraded nodes
What you still manage:
- Instance type selection and sizing
- Minimum, maximum, and desired scaling bounds
- Capacity type: on-demand vs Spot
- Node labels and taints
- Launch template decisions if you customise beyond defaults
- When to apply AMI updates (AWS publishes new versions; you deploy them)
- Rollout timing and update strategy
- Which pods land on which node groups
- Security posture: IAM roles, security groups, and node-level hardening. The Securing EKS Clusters guide covers the full EKS security model.
- Monitoring and alerting for node health and pod disruptions. See Monitoring EKS Clusters for what to watch.
- Cost control: instance families, Spot strategy, and over-provisioning
AWS does not automatically patch your nodes. When AWS releases a new EKS-optimized AMI with OS patches or a Kubernetes component update, those updates sit waiting until you deploy them. Nothing applies itself. You are responsible for triggering updates on a schedule that keeps your nodes current.
If you are currently writing scripts to bootstrap nodes, drain them before updates, or manage rolling AMI replacements — managed node groups handle all of that. If your bottleneck is something else (custom OS images, hardened kernel configs, or non-standard bootstrap logic) you may need self-managed nodes instead.
How managed node groups work#
When you create a managed node group, EKS creates an EC2 Auto Scaling Group in your account and attaches a launch template configured with the EKS-optimized AMI. That AMI includes kubelet, containerd, and the VPC CNI plugin, all pre-wired to connect to your cluster.
Each instance the ASG launches runs a bootstrap script automatically. The script calls the EKS API to fetch cluster configuration, starts kubelet, and registers the node with the Kubernetes control plane. Once registered, the node appears in kubectl get nodes and becomes available for scheduling.
Labels and taints you define on the node group are applied to every node at bootstrap time. A node group with role=gpu can receive GPU-intensive pods via node selectors. A node group with spot=true:NoSchedule ensures only tolerating pods land on Spot capacity.
For EKS networking, each node gets ENIs from the VPC CNI plugin and pods receive IP addresses directly from your subnet CIDR range.
Changes made directly to the auto-generated launch template outside the EKS API will put the node group into an inconsistent state and can break future updates. If you need custom configuration, supply your own launch template from the start rather than modifying the one EKS created.
When to use managed node groups#
Managed node groups are the right default for most EKS clusters:
- Most production EKS clusters. The automated lifecycle reduces operational work without giving up EC2 flexibility.
- Teams that want EC2 control without self-managing node lifecycle. You get instance type choice, DaemonSet support, and GPU support with less overhead.
- Mixed on-demand and Spot capacity. Run separate node groups for reliable critical workloads and cost-optimised interruptible ones.
- Multiple workload pools. Different node groups with different labels and taints let you isolate workloads with different resource, compliance, or scheduling requirements.
- Teams new to EKS. See Creating Your First EKS Cluster for a practical starting point.
When not to use managed node groups#
Managed node groups are not the right fit for every situation.
Use self-managed nodes when:
- You need deep OS-level customization the EKS-optimized AMI does not support: custom kernel parameters, modules, or security agents that require specific boot configuration.
- You have a highly customized AMI build pipeline that cannot integrate cleanly with managed node group constraints.
- You need specific user-data configuration that conflicts with how managed node groups inject their own bootstrap logic.
- You are using an AMI family or OS that managed node groups do not support, such as certain Windows builds or custom Linux distributions.
Use Fargate when:
- You want complete pod-level serverless isolation with no EC2 nodes to manage, patch, or right-size.
- Your workloads are irregular and short-lived and you want per-pod billing.
- Note: Fargate does not support DaemonSets, has no node-level visibility, and behaves differently from EC2 in terms of performance and scheduling. See EKS Node Groups Explained for a full comparison.
Managed node groups vs self-managed nodes vs Fargate#
| Capability | Managed Node Group | Self-Managed Nodes | Fargate |
|---|---|---|---|
| Provisioning | AWS creates and manages the ASG and launch template | You create and manage the ASG | No EC2 to provision; pods run on AWS-managed infrastructure |
| Upgrade responsibility | You trigger updates; AWS handles rolling replacement | You write and run your own drain-and-replace automation | AWS handles pod-level updates transparently |
| Node drain behavior | Automated by AWS during updates; respects PDBs | Manual or scripted by you | No nodes to drain |
| Custom AMI flexibility | Limited: AL2 and AL2023-based custom AMIs with caveats | Full control: any AMI you can boot | Not applicable |
| DaemonSet support | Yes | Yes | No |
| Spot support | Yes, via capacityType SPOT | Yes | No |
| GPU instances | Yes | Yes | Limited |
| EKS console visibility | Full: group status, version, health | Limited: nodes visible but not as a group | Yes, at the Fargate profile level |
| Operational overhead | Low: lifecycle managed by AWS | High: you own the full lifecycle | Very low: no nodes to manage |
| Best fit | Most production EKS clusters | Highly customized OS or AMI requirements | Serverless pods, irregular workloads |
Autoscaling and capacity planning#
Managed node groups scale the node fleet. They do not scale individual workloads. These are separate concerns and it helps to keep them distinct.
HPA scales your pods. It adds or removes replicas of your application based on CPU, memory, or custom metrics. Cluster Autoscaler scales your nodes. It adds or removes EC2 instances based on whether pods can be scheduled. They work together: HPA requests more pod copies, Cluster Autoscaler provides the nodes for those copies to run on.
Horizontal Pod Autoscaling (HPA) adds or removes pod replicas based on CPU, memory, or custom metrics. HPA works within the node capacity that already exists. If all nodes are full and you have no more room to schedule pods, HPA cannot help. New replicas will sit in Pending state until more nodes arrive.
Cluster Autoscaler watches for Pending pods and increases the desired capacity on the relevant node group to add nodes. When nodes are consistently underutilised, it scales down, draining pods off lightly loaded nodes and terminating the instances. To discover your node groups, the Cluster Autoscaler requires two EC2 tags on the underlying Auto Scaling Group:
k8s.io/cluster-autoscaler/enabled: "true"k8s.io/cluster-autoscaler/<cluster-name>: "owned"
Without both tags, the Cluster Autoscaler will not manage that node group.
Karpenter is a faster, more direct approach. Instead of adjusting ASG desired capacity and waiting for instances to bootstrap, Karpenter calls the EC2 API directly, selects the optimal instance type for each batch of pending pods, and provisions nodes more quickly. Some teams using Karpenter bypass managed node groups and use EC2 NodePools instead. For most teams not yet running Karpenter, the Cluster Autoscaler with managed node groups is the simpler starting point.
Multiple node groups let you separate workloads with different requirements. A common production pattern: one on-demand group for stateful services and the API tier, one Spot group for batch jobs and stateless services, and optionally a dedicated group for GPU workloads. Use Kubernetes node labels to express what a group is for and node taints to enforce that only the right workloads land there. A pod that does not tolerate the Spot taint will never be scheduled onto the Spot node group. This makes Spot opt-in rather than accidental.
AMI updates, Kubernetes version updates, and node draining#
There are three distinct types of changes that trigger a node replacement cycle in managed node groups. They all use the same rolling replacement mechanism, but they come from different sources and happen at different times.
AMI refreshes happen when AWS publishes a new EKS-optimised AMI with OS security patches, kernel updates, or updated container runtime versions. These do not change the Kubernetes version running on the node. You check whether a new AMI version is available and trigger the update yourself. Nothing applies automatically.
Kubernetes version updates are a bigger change. When you upgrade the EKS control plane to a new minor version, your node groups still run the previous version. You must then update the node groups separately to align them with the new control plane. See Upgrading EKS Clusters Safely for the full upgrade sequence and why the ordering matters.
EKS supports nodes running up to one minor version behind the control plane, but the specific supported skew may change across EKS releases. Check the current EKS documentation before planning upgrades. Running nodes significantly behind the control plane makes the next upgrade harder and is a common source of upgrade problems.
Launch template or configuration changes (modifying instance type, disk size, user data, or security groups) also trigger a rolling replacement when applied.
All three use the same rolling replacement flow:
- A new node launches with the updated AMI.
- Once ready and registered, one old node is cordoned: no new pods will schedule onto it.
- The old node is drained using the Kubernetes eviction API and existing pods are rescheduled elsewhere.
- The drained node is terminated.
- This repeats for every node in the group.
Analogy
A rolling update is like replacing the tyres on a moving car one at a time. You jack up one wheel, swap it out, lower the car, and move to the next. The car keeps rolling throughout because you never have more than one wheel off the ground at a time. maxUnavailable is how many wheels you are allowed to swap at once.
The updateConfig.maxUnavailable setting controls concurrency. maxUnavailable: 1 means one node is replaced at a time: safest, but slowest for large groups. Setting it to 2 or 3 speeds up replacements for big node groups.
# Check the current AMI release version your node group is running
aws eks describe-nodegroup \
--cluster-name my-cluster \
--nodegroup-name general-workers \
--query 'nodegroup.releaseVersion'
# Trigger an AMI update to the latest published version
aws eks update-nodegroup-version \
--cluster-name my-cluster \
--nodegroup-name general-workers
Managed node group updates respect pod disruption budgets. If a PDB prevents safe eviction, the drain waits until it can proceed. If the drain cannot complete within the timeout, the update fails. Before triggering node group updates, check that your PDBs and replica counts allow at least one pod per deployment to be evicted per node. A PDB set so tightly that no pod can be removed will stall the update and force a manual intervention.
Using Spot with managed node groups#
Managed node groups support Spot instances via capacityType: SPOT. For batch jobs, stateless web services, dev environments, and other interruption-tolerant workloads, Spot can reduce EC2 costs substantially compared to on-demand pricing.
Databases, message queue brokers, stateful caches, and any workload where a 2-minute shutdown window causes data loss or a service outage must run on on-demand nodes. Spot interruptions are not gradual — AWS gives a 2-minute notice and reclaims the instance. There is no negotiation.
Spot and on-demand should be separate node groups. Mixing them in a single group makes it harder to prevent critical workloads from landing on interruptible instances. Run one on-demand node group for services that must stay up, and one or more Spot node groups for cost-sensitive workloads.
Use a taint on the Spot node group so only pods that explicitly tolerate it are scheduled there:
managedNodeGroups:
- name: on-demand-workers
instanceType: m5.large
capacityType: ON_DEMAND
minSize: 2
maxSize: 10
privateNetworking: true
- name: spot-workers
instanceTypes:
- m5.large
- m5.xlarge
- m4.large
- m4.xlarge
capacityType: SPOT
minSize: 0
maxSize: 20
labels:
lifecycle: spot
taints:
- key: spot
value: "true"
effect: NoSchedule
When you specify multiple instance types, AWS can source Spot capacity from several pools. If m5.large capacity is unavailable, it falls back to m4.large or m5.xlarge. The more instance types you list, the more resilient your Spot node group is to interruptions and capacity shortages.
Install the AWS Node Termination Handler so nodes drain gracefully when a Spot interruption notice arrives:
helm repo add eks https://aws.github.io/eks-charts
helm install aws-node-termination-handler \
--namespace kube-system \
eks/aws-node-termination-handler
Launch templates, custom AMIs, and node auto repair#
By default, EKS generates a launch template for your managed node group. If you need custom configuration such as a hardened AMI, additional packages at boot, or custom user-data, you can supply your own launch template. There are constraints:
- The AMI must be derived from the EKS-optimized AL2 or AL2023 base. Fully custom AMIs are supported, but the bootstrap script must still register the node with EKS correctly.
- Some launch template settings conflict with managed node group behavior. Review the EKS documentation before customizing.
- When using a custom launch template, you take on responsibility for keeping that template’s AMI version updated.
Node auto repair is an optional feature that detects nodes in a degraded or unresponsive state and replaces them automatically. When enabled, EKS monitors node health and initiates replacement without manual intervention. This is useful in production clusters where a silently failed node might otherwise go unnoticed until it affects workloads.
Private subnet and networking considerations#
Managed node groups support privateNetworking: true, which places nodes in private subnets with no public IP. This is the recommended configuration for production clusters and is required for private EKS clusters.
Nodes in private subnets still need outbound access to several services:
- EKS API endpoint so kubelet can register and communicate with the control plane.
- Amazon ECR to pull container images. Use a VPC endpoint for ECR to avoid routing image pulls through NAT.
- Amazon S3 because ECR stores image layers in S3. An S3 VPC endpoint keeps this traffic inside the VPC.
- CloudWatch if you use Container Insights or the CloudWatch agent.
- Any other AWS service your workloads call directly.
Without these routes, node bootstrap can fail silently or pods will fail to start because images cannot be pulled. See EKS Networking Model for a full walkthrough of how VPC CNI and subnet routing work together.
eksctl configuration example#
A production-ready managed node group configuration in an eksctl cluster file:
managedNodeGroups:
- name: general-workers
instanceType: m5.large
capacityType: ON_DEMAND
minSize: 2
maxSize: 12
desiredCapacity: 4
privateNetworking: true
availabilityZones:
- eu-west-1a
- eu-west-1b
- eu-west-1c
labels:
role: general
environment: production
iam:
withAddonPolicies:
autoScaler: true
cloudWatch: true
albIngress: true
updateConfig:
maxUnavailable: 1
- name: spot-workers
instanceTypes:
- m5.large
- m5.xlarge
- m4.large
- m4.xlarge
capacityType: SPOT
minSize: 0
maxSize: 20
desiredCapacity: 2
privateNetworking: true
labels:
role: spot
lifecycle: spot
taints:
- key: spot
value: "true"
effect: NoSchedule
updateConfig:
maxUnavailable: 2
The Spot node group specifies multiple instance types for capacity diversity and applies a taint requiring tolerations. Critical workloads that lack the toleration will never be scheduled onto interruptible Spot capacity.
Common mistakes#
-
Assuming AWS patches nodes automatically. AWS publishes new EKS-optimized AMIs but does not apply them. Nodes only update when you trigger an update. Set a schedule and check for new AMI releases after every EKS version update.
-
Treating managed node groups as fully hands-off Kubernetes. Managed node groups reduce node lifecycle work. They do not remove responsibility for workload design, update timing, security group configuration, IAM policy correctness, or cost control.
-
Mixing Spot and on-demand in the same node group. Without separation, critical workloads can land on Spot nodes and get interrupted. Always taint Spot node groups to make Spot placement opt-in.
-
Upgrading the control plane but forgetting node groups. After a Kubernetes control plane upgrade, node groups still run the previous version. EKS supports nodes one minor version behind the control plane, but running further behind is unsupported. See Upgrading EKS Clusters Safely for the right upgrade sequence.
-
Not planning PDBs and replica counts before upgrades. If all replicas of a deployment sit on the same node, draining that node takes the service offline. If a PDB is set too restrictively, the drain stalls and the update fails. Before triggering updates, confirm replica counts are spread across nodes and PDBs allow at least one eviction per node.
-
Using one node group for every workload. A single flat node group makes it hard to isolate workloads with different resource profiles, compliance requirements, or Spot tolerance. Use multiple node groups with labels and taints from the start.
-
Misunderstanding Cluster Autoscaler tag requirements. Managed node groups are automatically discoverable by the Cluster Autoscaler. The
k8s.io/cluster-autoscaler/enabledandk8s.io/cluster-autoscaler/<cluster-name>tags are required for standard discovery. If you also want the autoscaler to honor specific node labels or taints for scale-from-zero behavior, you need additionalk8s.io/cluster-autoscaler/node-template/tags. Those extra tags are not required for basic scaling.
Pricing#
There is no additional charge for using managed node groups. You pay for the EC2 instances, EBS volumes, and any other AWS resources the node group creates, the same charges you would incur with self-managed nodes. The managed lifecycle layer itself is free.
Using Spot instances in managed node groups can reduce EC2 compute costs substantially for the right workloads. See AWS EC2 Spot Instances Explained for how Spot pricing and interruption work.
Related topics to read next#
- EKS Node Groups Explained: the broader comparison of managed, self-managed, and Fargate, including instance type selection and ENI pod limits.
- Upgrading EKS Clusters Safely: step-by-step upgrade sequence for control plane and node groups, including version skew constraints.
- Horizontal Pod Autoscaling: how to scale workloads within the node capacity your node groups provide.
- Monitoring EKS Clusters: Container Insights, CloudWatch metrics, and Prometheus for node and workload observability.
- Securing EKS Clusters: node IAM roles, security groups, RBAC, and network policies for a hardened cluster.
- IAM Roles for Service Accounts (IRSA): how to give individual workloads AWS permissions without broad node-level IAM policies.
- EKS Networking Model: how VPC CNI, subnets, and ENI limits interact with your node groups.
- AWS EC2 Spot Instances Explained: Spot pricing, interruption mechanics, and capacity pool behaviour explained.
- EC2 Launch Templates Explained: what launch templates do and how custom templates work with managed node groups.
- Creating Your First EKS Cluster: hands-on walkthrough of setting up a cluster with managed node groups using eksctl.
Frequently asked questions
What does AWS manage in an EKS managed node group?
AWS provisions the EC2 instances, creates and manages the underlying Auto Scaling Group and launch template, registers nodes with the cluster, and handles rolling node replacement during updates, including graceful pod draining. You manage instance type selection, scaling bounds, labels, taints, security group rules, add-ons, and the timing of when updates are applied.
Do managed node groups update automatically?
No. AWS makes new AMI versions available when EKS-optimised AMIs are updated, but your node group does not update automatically. You choose when to trigger an update via the console, CLI, or IaC, and AWS performs the rolling replacement. This gives you control over your maintenance windows.
Can I use custom AMIs or launch templates with managed node groups?
Yes, with limitations. You can provide a custom launch template to specify a custom AMI (AL2 or AL2023 based), user data, and other instance configuration. However, some launch template fields are reserved for AWS. For fully custom OS images or kernel configurations, self-managed node groups give you more control.
Can I run Spot instances in managed node groups?
Yes. Set capacityType: SPOT (or spot: true in eksctl) and specify multiple instance types to improve Spot availability. When a Spot interruption occurs, EKS drains the node before it is reclaimed. You should also install the AWS Node Termination Handler DaemonSet to react to Spot interruption notices more reliably.
When should I choose managed node groups over Fargate or self-managed nodes?
Choose managed node groups for most production workloads where you need DaemonSets, persistent storage, GPU instances, or fine-grained control over instance types and placement. Choose Fargate for workloads that need strong isolation or where you want zero node management. Choose self-managed nodes only when you need custom AMIs, specific kernel versions, or configurations that managed node groups do not expose.