Skip to content

Commit

Permalink
feat(eks): arm64 support (#9875)
Browse files Browse the repository at this point in the history
feat(eks): support ARM64 for self-managed and managed nodegroup

Closes: #9915 

- [x] self-managed nodegroups with `ARM64` support
- [x] managed nodegroups with `ARM64` support
- [x] cluster default capacity with `ARM64` support
- [x] implicitly determine the `amiType` from the `instanceType` to make it just works.
- [x] update README
- [x] integ and unit tests

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
pahud authored Sep 7, 2020
1 parent cce83dc commit ffb84c6
Show file tree
Hide file tree
Showing 8 changed files with 590 additions and 15 deletions.
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,31 @@ cluster.addNodegroup('nodegroup', {
});
```

### ARM64 Support

Instance types with `ARM64` architecture are supported in both managed nodegroup and self-managed capacity. Simply specify an ARM64 `instanceType` (such as `m6g.medium`), and the latest
Amazon Linux 2 AMI for ARM64 will be automatically selected.

```ts
// create a cluster with a default managed nodegroup
cluster = new eks.Cluster(this, 'Cluster', {
vpc,
mastersRole,
version: eks.KubernetesVersion.V1_17,
});

// add a managed ARM64 nodegroup
cluster.addNodegroup('extra-ng-arm', {
instanceType: new ec2.InstanceType('m6g.medium'),
minSize: 2,
});

// add a self-managed ARM64 nodegroup
cluster.addCapacity('self-ng-arm', {
instanceType: new ec2.InstanceType('m6g.medium'),
minCapacity: 2,
})
```

### Fargate

Expand Down
43 changes: 36 additions & 7 deletions packages/@aws-cdk/aws-eks/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AwsAuth } from './aws-auth';
import { ClusterResource, clusterArnComponents } from './cluster-resource';
import { FargateProfile, FargateProfileOptions } from './fargate-profile';
import { HelmChart, HelmChartOptions } from './helm-chart';
import { INSTANCE_TYPES } from './instance-types';
import { KubernetesManifest } from './k8s-manifest';
import { KubernetesObjectValue } from './k8s-object-value';
import { KubernetesPatch } from './k8s-patch';
Expand Down Expand Up @@ -1047,6 +1048,7 @@ export class Cluster extends ClusterBase {
new BottleRocketImage() :
new EksOptimizedImage({
nodeType: nodeTypeForInstanceType(options.instanceType),
cpuArch: cpuArchForInstanceType(options.instanceType),
kubernetesVersion: this.version.version,
}),
updateType: options.updateType,
Expand Down Expand Up @@ -1639,6 +1641,13 @@ export interface EksOptimizedImageProps {
*/
readonly nodeType?: NodeType;

/**
* What cpu architecture to retrieve the image for (arm64 or x86_64)
*
* @default CpuArch.X86_64
*/
readonly cpuArch?: CpuArch;

/**
* The Kubernetes version to use
*
Expand All @@ -1652,20 +1661,22 @@ export interface EksOptimizedImageProps {
*/
export class EksOptimizedImage implements ec2.IMachineImage {
private readonly nodeType?: NodeType;
private readonly cpuArch?: CpuArch;
private readonly kubernetesVersion?: string;

private readonly amiParameterName: string;

/**
* Constructs a new instance of the EcsOptimizedAmi class.
*/
public constructor(props: EksOptimizedImageProps = {}) {
this.nodeType = props.nodeType ?? NodeType.STANDARD;
this.cpuArch = props.cpuArch ?? CpuArch.X86_64;
this.kubernetesVersion = props.kubernetesVersion ?? LATEST_KUBERNETES_VERSION;

// set the SSM parameter name
this.amiParameterName = `/aws/service/eks/optimized-ami/${this.kubernetesVersion}/`
+ ( this.nodeType === NodeType.STANDARD ? 'amazon-linux-2/' : '' )
+ ( this.nodeType === NodeType.STANDARD ? this.cpuArch === CpuArch.X86_64 ?
'amazon-linux-2/' : 'amazon-linux-2-arm64/' :'' )
+ ( this.nodeType === NodeType.GPU ? 'amazon-linux-2-gpu/' : '' )
+ (this.nodeType === NodeType.INFERENTIA ? 'amazon-linux-2-gpu/' : '')
+ 'recommended/image_id';
Expand Down Expand Up @@ -1739,6 +1750,21 @@ export enum NodeType {
INFERENTIA = 'INFERENTIA',
}

/**
* CPU architecture
*/
export enum CpuArch {
/**
* arm64 CPU type
*/
ARM_64 = 'arm64',

/**
* x86_64 CPU type
*/
X86_64 = 'x86_64',
}

/**
* The type of compute resources to use for CoreDNS.
*/
Expand Down Expand Up @@ -1782,12 +1808,15 @@ export enum MachineImageType {
BOTTLEROCKET
}

const GPU_INSTANCETYPES = ['p2', 'p3', 'g4'];
const INFERENTIA_INSTANCETYPES = ['inf1'];

function nodeTypeForInstanceType(instanceType: ec2.InstanceType) {
return GPU_INSTANCETYPES.includes(instanceType.toString().substring(0, 2)) ? NodeType.GPU :
INFERENTIA_INSTANCETYPES.includes(instanceType.toString().substring(0, 4)) ? NodeType.INFERENTIA :
return INSTANCE_TYPES.gpu.includes(instanceType.toString().substring(0, 2)) ? NodeType.GPU :
INSTANCE_TYPES.inferentia.includes(instanceType.toString().substring(0, 4)) ? NodeType.INFERENTIA :
NodeType.STANDARD;
}

function cpuArchForInstanceType(instanceType: ec2.InstanceType) {
return INSTANCE_TYPES.graviton2.includes(instanceType.toString().substring(0, 3)) ? CpuArch.ARM_64 :
INSTANCE_TYPES.graviton.includes(instanceType.toString().substring(0, 2)) ? CpuArch.ARM_64 :
CpuArch.X86_64;
}

6 changes: 6 additions & 0 deletions packages/@aws-cdk/aws-eks/lib/instance-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const INSTANCE_TYPES = {
gpu: ['p2', 'p3', 'g2', 'g3', 'g4'],
inferentia: ['inf1'],
graviton: ['a1'],
graviton2: ['c6g', 'm6g', 'r6g'],
};
20 changes: 17 additions & 3 deletions packages/@aws-cdk/aws-eks/lib/managed-nodegroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IRole, ManagedPolicy, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import { Construct, IResource, Resource } from '@aws-cdk/core';
import { Cluster, ICluster } from './cluster';
import { CfnNodegroup } from './eks.generated';
import { INSTANCE_TYPES } from './instance-types';

/**
* NodeGroup interface
Expand All @@ -22,13 +23,17 @@ export interface INodegroup extends IResource {
*/
export enum NodegroupAmiType {
/**
* Amazon Linux 2
* Amazon Linux 2 (x86-64)
*/
AL2_X86_64 = 'AL2_x86_64',
/**
* Amazon Linux 2 with GPU support
*/
AL2_X86_64_GPU = 'AL2_x86_64_GPU',
/**
* Amazon Linux 2 (ARM-64)
*/
AL2_ARM_64 = 'AL2_ARM_64'
}

/**
Expand Down Expand Up @@ -73,7 +78,7 @@ export interface NodegroupOptions {
/**
* The AMI type for your node group.
*
* @default AL2_x86_64
* @default - auto-determined from the instanceType property.
*/
readonly amiType?: NodegroupAmiType;
/**
Expand Down Expand Up @@ -243,7 +248,8 @@ export class Nodegroup extends Resource implements INodegroup {
nodegroupName: props.nodegroupName,
nodeRole: this.role.roleArn,
subnets: this.cluster.vpc.selectSubnets(props.subnets).subnetIds,
amiType: props.amiType,
amiType: props.amiType ?? (props.instanceType ? getAmiTypeForInstanceType(props.instanceType).toString() :
undefined),
diskSize: props.diskSize,
forceUpdateEnabled: props.forceUpdate ?? true,
instanceTypes: props.instanceType ? [props.instanceType.toString()] : undefined,
Expand Down Expand Up @@ -282,5 +288,13 @@ export class Nodegroup extends Resource implements INodegroup {
});
this.nodegroupName = this.getResourceNameAttribute(resource.ref);
}
}

function getAmiTypeForInstanceType(instanceType: InstanceType) {
return INSTANCE_TYPES.graviton2.includes(instanceType.toString().substring(0, 3)) ? NodegroupAmiType.AL2_ARM_64 :
INSTANCE_TYPES.graviton.includes(instanceType.toString().substring(0, 2)) ? NodegroupAmiType.AL2_ARM_64 :
INSTANCE_TYPES.gpu.includes(instanceType.toString().substring(0, 2)) ? NodegroupAmiType.AL2_X86_64_GPU :
INSTANCE_TYPES.inferentia.includes(instanceType.toString().substring(0, 4)) ? NodegroupAmiType.AL2_X86_64_GPU :
NodegroupAmiType.AL2_X86_64;
}

Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,7 @@
"Ref": "VpcPrivateSubnet3SubnetF258B56E"
}
],
"AmiType": "AL2_x86_64",
"ForceUpdateEnabled": true,
"InstanceTypes": [
"m5.large"
Expand Down
Loading

0 comments on commit ffb84c6

Please sign in to comment.