Skip to content

Commit

Permalink
fix(eks): missing support for "InstanceTypes" attribute assignment fo…
Browse files Browse the repository at this point in the history
…r AL2023 AMIs
  • Loading branch information
guessi committed Mar 15, 2024
1 parent bbc624c commit d87fba6
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class EksClusterStack extends Stack {

this.assertCapacityArm();

this.assertAmazonLinux2();

this.assertAmazonLinux2023();

this.assertBottlerocket();

this.assertSpotCapacity();
Expand Down Expand Up @@ -312,14 +316,29 @@ class EksClusterStack extends Stack {
},
});
}
private assertAmazonLinux2() {
// add Amazon Linux 2 nodes
this.cluster.addAutoScalingGroupCapacity('BottlerocketNodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.AMAZON_LINUX_2,
});
}
private assertAmazonLinux2023() {
// add Amazon Linux 2023 nodes
this.cluster.addAutoScalingGroupCapacity('BottlerocketNodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.AMAZON_LINUX_2023,
});
}
private assertBottlerocket() {
// add bottlerocket nodes
this.cluster.addAutoScalingGroupCapacity('BottlerocketNodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.BOTTLEROCKET,
});

}
private assertCapacityX86() {
// add some x86_64 capacity to the cluster. The IAM instance role will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class EksClusterStack extends Stack {

this.assertCapacityArm();

this.assertAmazonLinux2();

this.assertAmazonLinux2023();

this.assertBottlerocket();

this.assertSpotCapacity();
Expand Down Expand Up @@ -288,14 +292,29 @@ class EksClusterStack extends Stack {
},
});
}
private assertAmazonLinux2() {
// add Amazon Linux2 nodes
this.cluster.addAutoScalingGroupCapacity('AmazonLinux2Nodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.AMAZON_LINUX_2,
});
}
private assertAmazonLinux2023() {
// add Amazon Linux2023 nodes
this.cluster.addAutoScalingGroupCapacity('AmazonLinux2Nodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.AMAZON_LINUX_2023,
});
}
private assertBottlerocket() {
// add bottlerocket nodes
this.cluster.addAutoScalingGroupCapacity('BottlerocketNodes', {
instanceType: new ec2.InstanceType('t3.small'),
minCapacity: 2,
machineImageType: eks.MachineImageType.BOTTLEROCKET,
});

}
private assertCapacityX86() {
// add some x86_64 capacity to the cluster. The IAM instance role will
Expand Down
6 changes: 5 additions & 1 deletion packages/aws-cdk-lib/aws-eks/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2461,9 +2461,13 @@ export enum DefaultCapacityType {
*/
export enum MachineImageType {
/**
* Amazon EKS-optimized Linux AMI
* Amazon EKS-optimized Linux AMI (AL2)
*/
AMAZON_LINUX_2,
/**
* Amazon EKS-optimized Linux AMI (AL2023)
*/
AMAZON_LINUX_2023,
/**
* Bottlerocket AMI
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/aws-cdk-lib/aws-eks/lib/managed-nodegroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,8 @@ export class Nodegroup extends Resource implements INodegroup {
* AMI types of different architectures. Make sure AL2 is always the first element, which will be the default
* AmiType if amiType and launchTemplateSpec are both undefined.
*/
const arm64AmiTypes: NodegroupAmiType[] = [NodegroupAmiType.AL2_ARM_64, NodegroupAmiType.BOTTLEROCKET_ARM_64];
const x8664AmiTypes: NodegroupAmiType[] = [NodegroupAmiType.AL2_X86_64, NodegroupAmiType.BOTTLEROCKET_X86_64,
const arm64AmiTypes: NodegroupAmiType[] = [NodegroupAmiType.AL2_ARM_64, NodegroupAmiType.AL2023_ARM_64_STANDARD, NodegroupAmiType.BOTTLEROCKET_ARM_64];
const x8664AmiTypes: NodegroupAmiType[] = [NodegroupAmiType.AL2_X86_64, NodegroupAmiType.AL2023_X86_64_STANDARD, NodegroupAmiType.BOTTLEROCKET_X86_64,
NodegroupAmiType.WINDOWS_CORE_2019_X86_64, NodegroupAmiType.WINDOWS_CORE_2022_X86_64,
NodegroupAmiType.WINDOWS_FULL_2019_X86_64, NodegroupAmiType.WINDOWS_FULL_2022_X86_64];
const windowsAmiTypes: NodegroupAmiType[] = [NodegroupAmiType.WINDOWS_CORE_2019_X86_64,
Expand Down
58 changes: 50 additions & 8 deletions packages/aws-cdk-lib/aws-eks/test/cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import * as kms from '../../aws-kms';
import * as lambda from '../../aws-lambda';
import * as cdk from '../../core';
import * as eks from '../lib';
import { HelmChart } from '../lib';
import { HelmChart, NodegroupAmiType } from '../lib';
import { KubectlProvider } from '../lib/kubectl-provider';
import { BottleRocketImage } from '../lib/private/bottlerocket';

/* eslint-disable max-len */

const CLUSTER_VERSION = eks.KubernetesVersion.V1_25;
const CLUSTER_VERSION = eks.KubernetesVersion.V1_29;

describe('cluster', () => {
test('can configure and access ALB controller', () => {
Expand All @@ -27,7 +27,7 @@ describe('cluster', () => {
const cluster = new eks.Cluster(stack, 'Cluster', {
version: CLUSTER_VERSION,
albController: {
version: eks.AlbControllerVersion.V2_4_1,
version: eks.AlbControllerVersion.V2_6_2,
},
});

Expand Down Expand Up @@ -132,7 +132,7 @@ describe('cluster', () => {
vpc: vpc,
vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }, { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }],
defaultCapacity: 0,
version: eks.KubernetesVersion.V1_21,
version: eks.KubernetesVersion.V1_29,
})).toThrow(/cannot select multiple subnet groups/);
});

Expand All @@ -142,7 +142,7 @@ describe('cluster', () => {
vpc: vpc,
vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }],
defaultCapacity: 0,
version: eks.KubernetesVersion.V1_21,
version: eks.KubernetesVersion.V1_29,
});

// THEN
Expand Down Expand Up @@ -1543,7 +1543,7 @@ describe('cluster', () => {

// THEN
expect(() => cluster.addAutoScalingGroupCapacity('MyCapcity', {
instanceType: new ec2.InstanceType('m3.xlargs'),
instanceType: new ec2.InstanceType('m3.xlarge'),
bootstrapEnabled: false,
bootstrapOptions: { awsApiRetryAttempts: 10 },
})).toThrow(/Cannot specify "bootstrapOptions" if "bootstrapEnabled" is false/);
Expand Down Expand Up @@ -1586,7 +1586,7 @@ describe('cluster', () => {
)).toEqual(true);
expect(Object.entries(parameters).some(
([k, v]) => k.startsWith('SsmParameterValueawsserviceeksoptimizedami') &&
(v as any).Default.includes('/1.25/'),
(v as any).Default.includes('/1.29/'),
)).toEqual(true);
});

Expand All @@ -1608,6 +1608,48 @@ describe('cluster', () => {
});
});

test('addNodegroup with AL2023_X86_64_STANDARD instance type comes with nodegroup with correct AmiType', () => {
// GIVEN
const { stack } = testFixtureNoVpc();

// WHEN
new eks.Cluster(stack, 'cluster', {
defaultCapacity: 0,
version: CLUSTER_VERSION,
prune: false,
defaultCapacityInstance: new ec2.InstanceType('m5.large'),
}).addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.AL2023_X86_64_STANDARD,
instanceTypes: [new ec2.InstanceType('m5.large')],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EKS::Nodegroup', {
AmiType: NodegroupAmiType.AL2023_X86_64_STANDARD,
});
});

test('addNodegroup with AL2023_ARM_64_STANDARD instance type comes with nodegroup with correct AmiType', () => {
// GIVEN
const { stack } = testFixtureNoVpc();

// WHEN
new eks.Cluster(stack, 'cluster', {
defaultCapacity: 0,
version: CLUSTER_VERSION,
prune: false,
defaultCapacityInstance: new ec2.InstanceType('m6g.medium'),
}).addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.AL2023_ARM_64_STANDARD,
instanceTypes: [new ec2.InstanceType('m6g.medium')],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EKS::Nodegroup', {
AmiType: NodegroupAmiType.AL2023_ARM_64_STANDARD,
});
});

test('addNodegroup with ARM64 instance type comes with nodegroup with correct AmiType', () => {
// GIVEN
const { stack } = testFixtureNoVpc();
Expand Down Expand Up @@ -1770,7 +1812,7 @@ describe('cluster', () => {
)).toEqual(true);
expect(Object.entries(parameters).some(
([k, v]) => k.startsWith('SsmParameterValueawsservicebottlerocketaws') &&
(v as any).Default.includes('/aws-k8s-1.25/'),
(v as any).Default.includes('/aws-k8s-1.29/'),
)).toEqual(true);
});

Expand Down
52 changes: 48 additions & 4 deletions packages/aws-cdk-lib/aws-eks/test/nodegroup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,50 @@ describe('node group', () => {
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64_GPU, BOTTLEROCKET_X86_64_NVIDIA, BOTTLEROCKET_ARM_64_NVIDIA or don't specify any/);
});

/**
* When LaunchTemplate is undefined, amiType is AL2023_X86_64_STANDARD and instanceTypes are not x86_64,
* we should throw an error.
*/
test('throws when LaunchTemplate is undefined, amiType is AL2023_X86_64_STANDARD and instanceTypes are not x86_64', () => {
// GIVEN
const { stack, vpc } = testFixture();
const cluster = new eks.Cluster(stack, 'Cluster', {
vpc,
defaultCapacity: 0,
version: CLUSTER_VERSION,
});
// THEN
expect(() => cluster.addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.AL2023_X86_64_STANDARD,
instanceTypes: [
new ec2.InstanceType('c6g.large'),
new ec2.InstanceType('t4g.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_ARM_64, AL2023_ARM_64_STANDARD, BOTTLEROCKET_ARM_64 or don't specify any/);
});

/**
* When LaunchTemplate is undefined, amiType is AL2023_ARM_64_STANDARD and instanceTypes are not ARM_64,
* we should throw an error.
*/
test('throws when LaunchTemplate is undefined, amiType is AL2023_ARM_64_STANDARD and instanceTypes are not ARM_64', () => {
// GIVEN
const { stack, vpc } = testFixture();
const cluster = new eks.Cluster(stack, 'Cluster', {
vpc,
defaultCapacity: 0,
version: CLUSTER_VERSION,
});
// THEN
expect(() => cluster.addNodegroupCapacity('ng', {
amiType: NodegroupAmiType.AL2023_ARM_64_STANDARD,
instanceTypes: [
new ec2.InstanceType('m5.large'),
new ec2.InstanceType('c5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
});

/**
* When LaunchTemplate is undefined, amiType is AL2_ARM_64 and instanceTypes are not ARM_64,
* we should throw an error.
Expand All @@ -580,7 +624,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
});

test('throws when AmiType is Windows and forbidden instanceType is selected', () => {
Expand Down Expand Up @@ -619,7 +663,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
});

test('throws when LaunchTemplate is undefined, amiType is BOTTLEROCKET_ARM_64_NVIDIA and instanceTypes are not GPU', () => {
Expand All @@ -637,7 +681,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
});

test('throws when LaunchTemplate is undefined, amiType is BOTTLEROCKET_X86_64_NVIDIA and instanceTypes are not GPU', () => {
Expand All @@ -655,7 +699,7 @@ describe('node group', () => {
new ec2.InstanceType('c5.large'),
new ec2.InstanceType('m5.large'),
],
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
})).toThrow(/The specified AMI does not match the instance types architecture, either specify one of AL2_X86_64, AL2023_X86_64_STANDARD, BOTTLEROCKET_X86_64, WINDOWS_CORE_2019_X86_64, WINDOWS_CORE_2022_X86_64, WINDOWS_FULL_2019_X86_64, WINDOWS_FULL_2022_X86_64 or don't specify any/);
});

/**
Expand Down

0 comments on commit d87fba6

Please sign in to comment.