Managed Node Groups are often seen as the "easy button" for EKS, but they can quietly lock you into specific configurations that become surprisingly difficult to change later.
Let’s see what a Managed Node Group actually does. Imagine you’ve got an EKS cluster, and you need some EC2 instances to run your pods. You could provision those yourself, but EKS offers Managed Node Groups as a way to automate it. When you create one, EKS provisions an EC2 Auto Scaling Group (ASG) for you, launches EC2 instances, joins them to your cluster, and keeps the AMI and Kubernetes version in sync.
Here’s a snippet of what an EKS Managed Node Group configuration looks like in Terraform:
resource "aws_eks_node_group" "example" {
cluster_name = "my-eks-cluster"
node_group_name = "example-nodes"
node_role_arn = aws_iam_role.eks_node_role.arn
subnet_ids = ["subnet-xxxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyyy"]
scaling_config {
desired_size = 3
max_size = 5
min_size = 1
}
update_config {
max_unavailable = 1
max_unavailable_percentage = 0 # Setting this to 0 means max_unavailable takes precedence
}
# This is the key part: EKS manages the AMI and Kubernetes version
# You can't just SSH in and update the kubelet. EKS handles it.
# The AMI ID is often managed by EKS or a specific EKS-optimized AMI version.
# Example: ami_type = "AL2_x86_64" or "BOTTLEROCKET_ARM_64"
# You can specify a custom AMI ID if needed, but it complicates updates.
ami_type = "AL2_x86_64"
release_version = "1.27.7-eks-7008459" # Example release version
instance_types = ["t3.medium"]
tags = {
"k8s.io/cluster-autoscaler/enabled" = "true"
"k8s.io/cluster-autoscaler/my-eks-cluster" = "owned"
"Name" = "example-node"
}
}
The primary problem Managed Node Groups solve is operational overhead. Instead of you managing the ASG, EC2 instances, bootstrapping kubelet, and rolling out AMI updates, EKS does it. When a new Kubernetes version or security patch for the AMI is released, EKS can automatically update your node groups. It does this by launching new instances with the updated AMI, joining them to the cluster, and then terminating the old ones, all while respecting your max_unavailable settings.
This automated update process is a huge win for security and staying current. You don’t have to plan complex migration strategies for your nodes when EKS releases a new version. EKS handles the rolling update, ensuring your cluster remains available.
However, this automation comes with a significant trade-off: immutability and control.
The mental model you need is that a Managed Node Group is a black box managed by EKS. You provide the desired state (instance type, scaling, Kubernetes version), and EKS figures out how to get there. You cannot directly SSH into these nodes and make arbitrary changes. If you need to install custom packages on the OS, modify kubelet configurations beyond what EKS exposes, or use an AMI that isn’t EKS-optimized, you’re likely going to fight the system.
Consider a scenario where you need a specific kernel module loaded on all your nodes for a custom CNI or a security agent. With a self-managed node group, you’d simply add it to your user data or bake it into your custom AMI. With a Managed Node Group, your options are limited to what the EKS-provided AMI supports or what can be configured via user_data during the initial launch. Modifying these post-launch is not the intended workflow.
The most common pattern for customization with Managed Node Groups is to use user_data for initial setup or to leverage EKS-provided mechanisms like custom AMIs if you absolutely must, but this adds complexity to the managed update process. If you specify a custom_ami_id, EKS will still manage the Kubernetes version on the instances, but it won’t update the AMI itself. You’d then be responsible for replacing nodes when your custom AMI needs patching.
The real power of Managed Node Groups lies in their integration with EKS’s lifecycle management. When EKS announces a new Kubernetes version, you can simply update the release_version in your node group configuration, and EKS will orchestrate the rollout of new nodes with the updated Kubernetes components. This is a stark contrast to self-managed nodes, where you’d typically need to provision new ASGs with updated AMIs and carefully drain/terminate old instances.
If you need fine-grained control over the EC2 instance lifecycle, the OS, or want to use non-standard AMIs, self-managed node groups are the way to go. You get complete control, but you also take on the full responsibility for bootstrapping, patching, and version synchronization.
The next thing you’ll likely encounter is trying to customize the network configuration of your nodes beyond what EKS provides out-of-the-box.