Amazon EKS — Bottlerocket and AMI Types

3 minute read

The operating system running on your EKS nodes affects security, performance, and maintenance. AWS provides several AMI options purpose-built for EKS.


EKS AMI Options

AMI Description Best For
Amazon Linux 2023 (AL2023) Latest EKS-optimized AMI, default for new clusters General production use
Amazon Linux 2 (AL2) Previous generation, still supported Legacy clusters
Bottlerocket Minimal, immutable OS built for containers Security-focused, hardened environments
Ubuntu Canonical-maintained EKS AMI Teams familiar with Ubuntu
Windows Windows Server for .NET workloads Windows containers
Custom AMI Your own AMI based on any of the above Special requirements

Amazon Linux 2023 (AL2023)

AL2023 is the default and recommended AMI for new EKS clusters.

Key Features

  • Based on Fedora, optimized for AWS
  • dnf package manager (replaces yum)
  • SELinux enabled by default
  • Kernel 6.x with eBPF support
  • containerd as the container runtime
  • Faster boot times than AL2

Retrieving the Latest AL2023 AMI

aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.29/amazon-linux-2023/x86_64/standard/recommended/image_id \
  --query 'Parameter.Value' --output text

Using AL2023 with eksctl

managedNodeGroups:
  - name: al2023-nodes
    amiFamily: AmazonLinux2023
    instanceType: m6i.xlarge
    desiredCapacity: 3

Bottlerocket

Bottlerocket is a purpose-built, minimal, immutable OS designed specifically for running containers.

Why Bottlerocket?

Feature Bottlerocket Standard Linux
Attack surface Minimal — no shell, no package manager on host Full OS with hundreds of packages
Updates Atomic, image-based updates Package-by-package updates
Rollback Built-in A/B partition rollback Manual/complex rollback
Configuration API-driven (TOML) SSH + scripts
Security SELinux enforcing, dm-verity, read-only root Varies by configuration
Compliance CIS Benchmark hardened out of the box Requires manual hardening

How Bottlerocket Differs

Standard Linux:
┌──────────────────────────┐
│ Shell (bash)             │
│ Package manager (yum)    │
│ SSH server               │
│ Hundreds of utilities    │
│ Container runtime        │
│ kubelet                  │
└──────────────────────────┘

Bottlerocket:
┌──────────────────────────┐
│ Container runtime        │
│ kubelet                  │
│ API server (for config)  │
│ (that's it)              │
└──────────────────────────┘

Using Bottlerocket with EKS

managedNodeGroups:
  - name: bottlerocket-nodes
    amiFamily: Bottlerocket
    instanceType: m6i.xlarge
    desiredCapacity: 3
    bottlerocket:
      settings:
        kubernetes:
          maxPods: 58

Accessing Bottlerocket Nodes

There’s no SSH by default. For debugging, use the admin container:

# Enable admin container via user data
[settings.host-containers.admin]
enabled = true

Or use SSM Session Manager:

aws ssm start-session --target i-1234567890abcdef0

Bottlerocket Updates

Bottlerocket uses an image-based update model with A/B partitions:

# Check for updates (from the control container or API)
apiclient update check

# Apply update
apiclient update apply

# Reboot into the new partition
apiclient reboot

If the new version fails to boot, Bottlerocket automatically rolls back to the previous partition.


AL2023 vs Bottlerocket

Feature AL2023 Bottlerocket
Package manager dnf (can install packages) None (immutable)
SSH access Yes (with key) No (admin container or SSM)
Security posture Good (SELinux available) Excellent (minimal surface, dm-verity)
Update model Package updates (yum/dnf) Image-based A/B updates
Rollback Manual Automatic A/B partition
Debugging SSH, full toolset Admin container, SSM
Learning curve Familiar Linux New paradigm
CIS hardened Manual hardening needed Out of the box
Best for General workloads Security-sensitive, compliance

Custom AMI Considerations

When the default AMIs don’t meet your needs, build custom AMIs:

When to Build Custom AMIs

  • Pre-install security agents (CrowdStrike, Datadog, etc.)
  • Custom kernel modules or parameters
  • Specific compliance requirements (FIPS, STIG)
  • Pre-pulled container images for faster startup
  • Custom monitoring agents

Building on Top of EKS AMIs

Always start from an EKS-optimized AMI — don’t build from scratch:

# Find the base AMI
BASE_AMI=$(aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.29/amazon-linux-2023/x86_64/standard/recommended/image_id \
  --query 'Parameter.Value' --output text)

echo "Base AMI: $BASE_AMI"

Then customize with Packer (see Self-Managed Nodes for the Packer template).

AMI Update Strategy

Custom AMIs need a rebuild pipeline:

  1. AWS releases a new EKS-optimized AMI (monthly-ish)
  2. Your pipeline rebuilds your custom AMI on top of the new base
  3. Update the launch template with the new AMI ID
  4. Trigger a rolling update on the node group
# Check latest AMI version
aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.29/amazon-linux-2023/x86_64/standard/recommended/release_version \
  --query 'Parameter.Value' --output text

Graviton (ARM) AMIs

All AMI types are available for Graviton (ARM) instances:

# AL2023 ARM AMI
aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.29/amazon-linux-2023/arm64/standard/recommended/image_id \
  --query 'Parameter.Value' --output text
managedNodeGroups:
  - name: graviton-nodes
    amiFamily: AmazonLinux2023
    instanceType: m7g.xlarge    # Graviton3
    desiredCapacity: 3

Important: Your container images must be built for ARM (or multi-architecture). x86 images won’t run on Graviton nodes.


Best Practices

  1. Use AL2023 as the default — it’s the most supported and well-tested option
  2. Consider Bottlerocket for security-sensitive workloads — minimal attack surface, automatic rollback
  3. Avoid custom AMIs unless necessary — they add maintenance burden
  4. Automate custom AMI builds with a CI/CD pipeline that triggers on new base AMI releases
  5. Test Bottlerocket in a separate node group before migrating production workloads
  6. Use multi-arch images if mixing x86 and Graviton (ARM) nodes

Updated: