Helper functions and constants for EKS node configuration, instance type classification, and user data generation.
Generate bootstrap scripts for EKS worker nodes with different AMI types.
/**
* Generate Amazon Linux 2 user data for EKS nodes
* @param cluster - EKS cluster
* @param autoScalingGroup - Auto Scaling Group for the nodes
* @param options - Bootstrap configuration options
* @returns Array of shell commands for user data
*/
function renderAmazonLinuxUserData(
cluster: ICluster,
autoScalingGroup: autoscaling.AutoScalingGroup,
options?: BootstrapOptions
): string[];
/**
* Generate Bottlerocket user data for EKS nodes
* @param cluster - EKS cluster
* @returns Array of TOML configuration lines
*/
function renderBottlerocketUserData(cluster: ICluster): string[];Usage Examples:
import * as eks from "@aws-cdk/aws-eks";
import * as autoscaling from "@aws-cdk/aws-autoscaling";
import * as ec2 from "@aws-cdk/aws-ec2";
// Create Auto Scaling Group with Amazon Linux 2
const asg = new autoscaling.AutoScalingGroup(this, "WorkerNodes", {
vpc: cluster.vpc,
instanceType: new ec2.InstanceType("t3.medium"),
machineImage: new eks.EksOptimizedImage({
kubernetesVersion: "1.21",
nodeType: eks.NodeType.STANDARD,
}),
});
// Generate user data for Amazon Linux 2 nodes
const userData = eks.renderAmazonLinuxUserData(cluster, asg, {
useMaxPods: true,
enableDockerBridge: false,
kubeletExtraArgs: "--max-pods=110",
awsApiRetryAttempts: 3,
});
asg.addUserData(...userData);
// Generate user data for Bottlerocket nodes
const bottlerocketAsg = new autoscaling.AutoScalingGroup(this, "BottlerocketNodes", {
vpc: cluster.vpc,
instanceType: new ec2.InstanceType("t3.medium"),
machineImage: new eks.EksOptimizedImage({
kubernetesVersion: "1.21",
nodeType: eks.NodeType.STANDARD,
cpuArch: eks.CpuArch.X86_64,
}),
});
const bottlerocketUserData = eks.renderBottlerocketUserData(cluster);
bottlerocketAsg.addUserData(...bottlerocketUserData);Configuration options for EKS node bootstrap process.
/**
* Bootstrap configuration options for EKS nodes
*/
interface BootstrapOptions {
/** Additional kubelet arguments */
readonly kubeletExtraArgs?: string;
/** Use max pods configuration */
readonly useMaxPods?: boolean;
/** Enable Docker bridge network */
readonly enableDockerBridge?: boolean;
/** Docker daemon configuration JSON */
readonly dockerConfigJson?: string;
/** DNS cluster IP address */
readonly dnsClusterIp?: string;
/** Additional bootstrap script arguments */
readonly additionalArgs?: string;
/** AWS API retry attempts */
readonly awsApiRetryAttempts?: number;
/** Container runtime configuration */
readonly containerRuntime?: ContainerRuntime;
}
/**
* Container runtime options
*/
enum ContainerRuntime {
/** Docker container runtime */
DOCKER = "docker",
/** containerd container runtime */
CONTAINERD = "containerd"
}Node lifecycle labels for scheduling and taints.
/**
* Node lifecycle labels for Kubernetes scheduling
*/
enum LifecycleLabel {
/** On-Demand instances */
ON_DEMAND = "OnDemand",
/** Spot instances */
SPOT = "Ec2Spot"
}Usage in Node Labels:
// Automatic lifecycle labeling based on instance type
const spotAsg = new autoscaling.AutoScalingGroup(this, "SpotNodes", {
vpc: cluster.vpc,
instanceType: new ec2.InstanceType("t3.medium"),
spotPrice: "0.05", // Enables spot instances
machineImage: new eks.EksOptimizedImage(),
});
// User data will automatically include:
// --node-labels lifecycle=Ec2Spot
// --register-with-taints=spotInstance=true:PreferNoSchedule
// On-demand instances get:
// --node-labels lifecycle=OnDemandConstants for categorizing EC2 instance types by capabilities.
/**
* Instance type classification constants
*/
const INSTANCE_TYPES: {
/** GPU-enabled instance families */
readonly gpu: string[];
/** AWS Inferentia instance families */
readonly inferentia: string[];
/** ARM-based Graviton instance families */
readonly graviton: string[];
/** ARM-based Graviton2 instance families */
readonly graviton2: string[];
};Instance Type Categories:
// GPU instances for machine learning workloads
INSTANCE_TYPES.gpu = ['p2', 'p3', 'g2', 'g3', 'g4'];
// Inferentia instances for ML inference
INSTANCE_TYPES.inferentia = ['inf1'];
// First-generation Graviton (ARM) instances
INSTANCE_TYPES.graviton = ['a1'];
// Second-generation Graviton2 (ARM) instances
INSTANCE_TYPES.graviton2 = ['c6g', 'm6g', 'r6g', 't4g'];Usage Examples:
import * as eks from "@aws-cdk/aws-eks";
import * as ec2 from "@aws-cdk/aws-ec2";
// Check if instance type requires GPU-optimized AMI
function requiresGpuAmi(instanceType: ec2.InstanceType): boolean {
const family = instanceType.toString().split('.')[0];
return eks.INSTANCE_TYPES.gpu.includes(family);
}
// Select appropriate AMI based on instance type
function selectOptimizedImage(instanceType: ec2.InstanceType): eks.EksOptimizedImage {
const family = instanceType.toString().split('.')[0];
if (eks.INSTANCE_TYPES.gpu.includes(family)) {
return new eks.EksOptimizedImage({
nodeType: eks.NodeType.GPU,
cpuArch: eks.CpuArch.X86_64,
});
}
if (eks.INSTANCE_TYPES.graviton2.includes(family)) {
return new eks.EksOptimizedImage({
nodeType: eks.NodeType.STANDARD,
cpuArch: eks.CpuArch.ARM_64,
});
}
if (eks.INSTANCE_TYPES.inferentia.includes(family)) {
return new eks.EksOptimizedImage({
nodeType: eks.NodeType.INFERENTIA,
cpuArch: eks.CpuArch.X86_64,
});
}
// Default to standard x86_64
return new eks.EksOptimizedImage({
nodeType: eks.NodeType.STANDARD,
cpuArch: eks.CpuArch.X86_64,
});
}
// Create instance-type-appropriate node group
const gpuNodeGroup = cluster.addNodegroupCapacity("GpuNodes", {
instanceTypes: [new ec2.InstanceType("p3.2xlarge")],
amiType: eks.NodegroupAmiType.AL2_X86_64_GPU,
});
const armNodeGroup = cluster.addNodegroupCapacity("ArmNodes", {
instanceTypes: [new ec2.InstanceType("t4g.medium")],
amiType: eks.NodegroupAmiType.AL2_ARM_64,
});// Advanced bootstrap configuration for production workloads
const productionBootstrapOptions: eks.BootstrapOptions = {
// Optimize for high pod density
useMaxPods: true,
kubeletExtraArgs: [
"--max-pods=110",
"--kube-reserved=cpu=250m,memory=1Gi,ephemeral-storage=1Gi",
"--system-reserved=cpu=250m,memory=1Gi,ephemeral-storage=1Gi",
"--eviction-hard=memory.available<500Mi,nodefs.available<10%",
].join(" "),
// Configure container runtime
enableDockerBridge: false,
containerRuntime: eks.ContainerRuntime.CONTAINERD,
// Network and API configuration
awsApiRetryAttempts: 5,
dnsClusterIp: "172.20.0.10",
// Custom Docker configuration for private registries
dockerConfigJson: JSON.stringify({
"auths": {
"my-registry.com": {
"auth": "base64-encoded-credentials"
}
}
}),
// Additional bootstrap arguments
additionalArgs: "--container-runtime containerd --cni-version v0.8.7",
};
const userData = eks.renderAmazonLinuxUserData(cluster, asg, productionBootstrapOptions);// Best practice: Architecture-aware node group creation
function createOptimizedNodeGroup(
cluster: eks.ICluster,
instanceType: ec2.InstanceType,
options: eks.NodegroupOptions = {}
): eks.Nodegroup {
const family = instanceType.toString().split('.')[0];
// Determine appropriate AMI type
let amiType: eks.NodegroupAmiType;
if (eks.INSTANCE_TYPES.gpu.includes(family)) {
amiType = eks.NodegroupAmiType.AL2_X86_64_GPU;
} else if (eks.INSTANCE_TYPES.graviton2.includes(family)) {
amiType = eks.NodegroupAmiType.AL2_ARM_64;
} else {
amiType = eks.NodegroupAmiType.AL2_X86_64;
}
return cluster.addNodegroupCapacity(`${family}-nodes`, {
instanceTypes: [instanceType],
amiType,
...options,
});
}