> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/terraform-aws-modules/terraform-aws-eks/llms.txt
> Use this file to discover all available pages before exploring further.

# EKS Managed Node Group

> Deploy an EKS cluster with AWS-managed EC2 node groups on Amazon Linux 2023 and Bottlerocket AMIs.

EKS managed node groups (MNG) let AWS handle the provisioning, patching, and graceful draining of EC2 worker nodes. You retain full control over instance types, AMI selection, sizing, and node-level configuration while AWS owns the underlying Auto Scaling group lifecycle.

This example demonstrates two separate clusters — one using the Amazon Linux 2023 (AL2023) AMI and one using Bottlerocket — to show how the `eks_managed_node_groups` map works with different operating systems.

## Prerequisites

* AWS credentials with permissions to create EKS, EC2, IAM, and VPC resources
* Terraform >= 1.5.7
* AWS provider >= 6.28
* The example provisions its own VPC — no pre-existing VPC is required

## VPC and shared locals

Both clusters share a common VPC defined in `main.tf`.

```hcl theme={null}
provider "aws" {
  region = local.region
}

data "aws_availability_zones" "available" {
  # Exclude local zones
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}

locals {
  name   = "ex-eks-mng"
  region = "eu-west-1"

  vpc_cidr = "10.0.0.0/16"
  azs      = slice(data.aws_availability_zones.available.names, 0, 3)

  tags = {
    Example    = local.name
    GithubRepo = "terraform-aws-eks"
    GithubOrg  = "terraform-aws-modules"
  }
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 6.0"

  name = local.name
  cidr = local.vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
  public_subnets  = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
  intra_subnets   = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)]

  enable_nat_gateway = true
  single_nat_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }

  tags = local.tags
}
```

## Amazon Linux 2023 cluster (`eks-al2023.tf`)

AL2023 is the default AMI type for EKS managed node groups starting with Kubernetes 1.30. It uses `nodeadm` for node initialization, and additional configuration can be injected via `cloudinit_pre_nodeadm`.

```hcl theme={null}
module "eks_al2023" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 21.0"

  name               = "${local.name}-al2023"
  kubernetes_version = "1.33"

  # EKS Addons
  addons = {
    coredns = {}
    eks-pod-identity-agent = {
      before_compute = true
    }
    kube-proxy = {}
    vpc-cni = {
      before_compute = true
    }
  }

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  eks_managed_node_groups = {
    example = {
      # Starting on 1.30, AL2023 is the default AMI type for EKS managed node groups
      instance_types = ["m6i.large"]
      ami_type       = "AL2023_x86_64_STANDARD"

      min_size = 2
      max_size = 5
      # This value is ignored after the initial creation
      # https://github.com/bryantbiggs/eks-desired-size-hack
      desired_size = 2

      # This is not required - demonstrates how to pass additional configuration to nodeadm
      # Ref https://awslabs.github.io/amazon-eks-ami/nodeadm/doc/api/
      cloudinit_pre_nodeadm = [
        {
          content_type = "application/node.eks.aws"
          content      = <<-EOT
            ---
            apiVersion: node.eks.aws/v1alpha1
            kind: NodeConfig
            spec:
              kubelet:
                config:
                  shutdownGracePeriod: 30s
          EOT
        }
      ]
    }
  }

  tags = local.tags
}
```

## Bottlerocket cluster (`eks-bottlerocket.tf`)

Bottlerocket is a Linux-based OS purpose-built for container workloads. Node configuration is injected via the `bootstrap_extra_args` field using TOML syntax.

```hcl theme={null}
module "eks_bottlerocket" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 21.0"

  name               = "${local.name}-bottlerocket"
  kubernetes_version = "1.33"

  # EKS Addons
  addons = {
    coredns = {}
    eks-pod-identity-agent = {
      before_compute = true
    }
    kube-proxy = {}
    vpc-cni = {
      before_compute = true
    }
  }

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  eks_managed_node_groups = {
    example = {
      ami_type       = "BOTTLEROCKET_x86_64"
      instance_types = ["m6i.large"]

      min_size = 2
      max_size = 5
      # This value is ignored after the initial creation
      # https://github.com/bryantbiggs/eks-desired-size-hack
      desired_size = 2

      # This is not required - demonstrates how to pass additional configuration
      # Ref https://bottlerocket.dev/en/os/1.19.x/api/settings/
      bootstrap_extra_args = <<-EOT
        # The admin host container provides SSH access and runs with "superpowers".
        # It is disabled by default, but can be disabled explicitly.
        [settings.host-containers.admin]
        enabled = false

        # The control host container provides out-of-band access via SSM.
        # It is enabled by default, and can be disabled if you do not expect to use SSM.
        # This could leave you with no way to access the API and change settings on an existing node!
        [settings.host-containers.control]
        enabled = true

        # extra args added
        [settings.kernel]
        lockdown = "integrity"
      EOT
    }
  }

  tags = local.tags
}
```

## Key configuration options

### AMI types

| `ami_type` value | OS | Notes |
| - | - | - |
| `AL2023_x86_64_STANDARD` | Amazon Linux 2023 (x86) | Default from Kubernetes 1.30+ |
| `AL2023_ARM_64_STANDARD` | Amazon Linux 2023 (ARM) | For Graviton instances |
| `BOTTLEROCKET_x86_64` | Bottlerocket (x86) | TOML-based configuration |
| `BOTTLEROCKET_ARM_64` | Bottlerocket (ARM) | For Graviton instances |

### `before_compute` addon flag

Setting `before_compute = true` on `vpc-cni` and `eks-pod-identity-agent` ensures those addons are installed before the first node joins the cluster, preventing race conditions where pods start before the CNI is ready.

### `desired_size` and drift

`desired_size` is only respected on the initial creation of the node group. After creation, the Auto Scaling group's actual desired capacity is the source of truth. See [eks-desired-size-hack](https://github.com/bryantbiggs/eks-desired-size-hack) for a workaround pattern.

<Tip>
  Use `use_latest_ami_release_version = true` on a node group to automatically track the latest patched AMI release for the configured AMI type and Kubernetes version.
</Tip>

## Deploy

<Steps>
  <Step title="Initialize Terraform">
    ```bash theme={null}
    terraform init
    ```
  </Step>

  <Step title="Review the plan">
    ```bash theme={null}
    terraform plan
    ```
  </Step>

  <Step title="Apply">
    Both clusters are created together. Expect 15–20 minutes for all resources.

    ```bash theme={null}
    terraform apply
    ```
  </Step>

  <Step title="Configure kubectl">
    ```bash theme={null}
    # For the AL2023 cluster
    aws eks update-kubeconfig --region eu-west-1 --name ex-eks-mng-al2023

    # For the Bottlerocket cluster
    aws eks update-kubeconfig --region eu-west-1 --name ex-eks-mng-bottlerocket
    ```
  </Step>
</Steps>

## Key outputs

| Output | Description |
| - | - |
| `cluster_name` | Name of the EKS cluster |
| `cluster_endpoint` | Kubernetes API server endpoint |
| `eks_managed_node_groups` | Map of attributes for all managed node groups |
| `eks_managed_node_groups_autoscaling_group_names` | Auto Scaling group names for each node group |

## Full example on GitHub

[View the complete example](https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples/eks-managed-node-group) including `outputs.tf`, `variables.tf`, and `versions.tf`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.