Skip to content

Commit

Permalink
feat(nodegroup): use the latest recommended AMIs from the SSM store
Browse files Browse the repository at this point in the history
- Default to the latest recommended AMI IDs from the AWS SSM Parameter Store.
- Add new `NodeGroupOption`: `gpu` to use the latest recommended EKS
  Optimized Linux AMI with GPU support.

See for more details:
  - https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html
  - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html
  - https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html
  • Loading branch information
metral committed Apr 6, 2020
1 parent 643a2ec commit 17dec48
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 60 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

### Improvements

- feat(nodegroup): use the latest recommended AMIs from the SSM store
[#366](https://github.com/pulumi/pulumi-eks/pull/366)
- feat(cluster): support HTTP(S) proxy for cluster readiness & OIDC config
[#364](https://github.com/pulumi/pulumi-eks/pull/364)
- deps(pulumi): bump node and go pulumi/pulumi to v1.13.1
Expand Down
30 changes: 26 additions & 4 deletions nodejs/eks/cluster.ts
Expand Up @@ -305,7 +305,8 @@ export function createCore(name: string, args: ClusterOptions, parent: pulumi.Co
args.minSize ||
args.maxSize ||
args.desiredCapacity ||
args.nodeAmiId)) {
args.nodeAmiId ||
args.gpu)) {
throw new Error("Setting nodeGroupOptions, and any set of singular node group option(s) on the cluster, is mutually exclusive. Choose a single approach.");
}

Expand All @@ -321,6 +322,7 @@ export function createCore(name: string, args: ClusterOptions, parent: pulumi.Co
maxSize: args.maxSize,
desiredCapacity: args.desiredCapacity,
amiId: args.nodeAmiId,
gpu: args.gpu,
version: args.version,
};

Expand Down Expand Up @@ -880,12 +882,32 @@ export interface ClusterOptions {
customInstanceRolePolicy?: pulumi.Input<string>;

/**
* The AMI to use for worker nodes. Defaults to the value of Amazon EKS - Optimized AMI if no value is provided.
* More information about the AWS eks optimized ami is available at https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html.
* Use the information provided by AWS if you want to build your own AMI.
* The AMI ID to use for the worker nodes.
*
* Defaults to the latest recommended EKS Optimized Linux AMI from the
* AWS Systems Manager Parameter Store.
*
* Note: `nodeAmiId` and `gpu` are mutually exclusive.
*
* See for more details:
* - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html.
*/
nodeAmiId?: pulumi.Input<string>;

/**
* Use the latest recommended EKS Optimized Linux AMI with GPU support for
* the worker nodes from the AWS Systems Manager Parameter Store.
*
* Defaults to false.
*
* Note: `gpu` and `nodeAmiId` are mutually exclusive.
*
* See for more details:
* - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html.
* - https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html
*/
gpu?: pulumi.Input<boolean>;

/**
* Public key material for SSH access to worker nodes. See allowed formats at:
* https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html
Expand Down
15 changes: 15 additions & 0 deletions nodejs/eks/examples/examples_test.go
Expand Up @@ -366,6 +366,21 @@ func TestAccTagInputTypes(t *testing.T) {
integration.ProgramTest(t, &test)
}

func TestAccNodegroupOptions(t *testing.T) {
test := getJSBaseOptions(t).
With(integration.ProgramTestOptions{
Dir: path.Join(getCwd(t), "tests", "nodegroup-options"),
ExtraRuntimeValidation: func(t *testing.T, info integration.RuntimeValidationStackInfo) {
utils.RunEKSSmokeTest(t,
info.Deployment.Resources,
info.Outputs["kubeconfig"],
)
},
})

integration.ProgramTest(t, &test)
}

func TestAccMigrateNodeGroups(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
Expand Down
3 changes: 3 additions & 0 deletions nodejs/eks/examples/tests/nodegroup-options/Pulumi.yaml
@@ -0,0 +1,3 @@
name: test-nodegroup-options
description: Tests nodegroup options
runtime: nodejs
3 changes: 3 additions & 0 deletions nodejs/eks/examples/tests/nodegroup-options/README.md
@@ -0,0 +1,3 @@
# tests/nodegroup-options

Tests nodegroup options: gpu.
12 changes: 12 additions & 0 deletions nodejs/eks/examples/tests/nodegroup-options/index.ts
@@ -0,0 +1,12 @@
import * as eks from "@pulumi/eks";
import * as pulumi from "@pulumi/pulumi";

const projectName = pulumi.getProject();

const cluster = new eks.Cluster(`${projectName}`, {
deployDashboard: false,
gpu: true,
});

// Export the cluster kubeconfig.
export const kubeconfig = cluster.kubeconfig;
10 changes: 10 additions & 0 deletions nodejs/eks/examples/tests/nodegroup-options/package.json
@@ -0,0 +1,10 @@
{
"name": "example-nodegroup-options",
"devDependencies": {
"typescript": "^3.0.0"
},
"dependencies": {
"@pulumi/pulumi": "^1.0.0",
"@pulumi/eks": "latest"
}
}
24 changes: 24 additions & 0 deletions nodejs/eks/examples/tests/nodegroup-options/tsconfig.json
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"outDir": "bin",
"target": "es6",
"lib": [
"es6"
],
"module": "commonjs",
"moduleResolution": "node",
"declaration": true,
"sourceMap": true,
"stripInternal": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true,
"strictNullChecks": true
},
"files": [
"index.ts"
]
}
92 changes: 36 additions & 56 deletions nodejs/eks/nodegroup.ts
Expand Up @@ -116,13 +116,32 @@ export interface NodeGroupBaseOptions {
maxSize?: pulumi.Input<number>;

/**
* The AMI to use for worker nodes. Defaults to the current value of Amazon EKS - Optimized AMI at time of resource
* creation if no value is provided. More information about the AWS eks optimized ami is available at
* https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html. Use the information provided by AWS if
* you want to build your own AMI.
* The AMI ID to use for the worker nodes.
*
* Defaults to the latest recommended EKS Optimized Linux AMI from the
* AWS Systems Manager Parameter Store.
*
* Note: `amiId` and `gpu` are mutually exclusive.
*
* See for more details:
* - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html.
*/
amiId?: pulumi.Input<string>;

/**
* Use the latest recommended EKS Optimized Linux AMI with GPU support for
* the worker nodes from the AWS Systems Manager Parameter Store.
*
* Defaults to false.
*
* Note: `gpu` and `amiId` are mutually exclusive.
*
* See for more details:
* - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html.
* - https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html
*/
gpu?: pulumi.Input<boolean>;

/**
* Custom k8s node labels to be attached to each woker node. Adds the given key/value pairs to the `--node-labels`
* kubelet argument.
Expand Down Expand Up @@ -291,6 +310,10 @@ export function createNodeGroup(name: string, args: NodeGroupOptions, parent: pu
throw new Error("nodePublicKey and keyName are mutually exclusive. Choose a single approach");
}

if (args.amiId && args.gpu) {
throw new Error("amiId and gpu are mutually exclusive.");
}

let nodeSecurityGroup: aws.ec2.SecurityGroup;
const cfnStackDeps: Array<pulumi.Resource> = [];

Expand Down Expand Up @@ -391,59 +414,16 @@ ${customUserData}
`;
});

let amiId: pulumi.Input<string> = args.amiId!;
let ignoreChanges: string[] = [];
if (args.amiId === undefined) {
const version = pulumi.output(args.version || core.cluster.version);
const version = pulumi.output(args.version || core.cluster.version);

// https://docs.aws.amazon.com/eks/latest/userguide/retrieve-ami-id.html
let amiId: pulumi.Input<string> | undefined = args.amiId;
if (!amiId) {
const amiType = args.gpu ? "amazon-linux-2-gpu" : "amazon-linux-2";
amiId = version.apply(v => {
const filters: { name: string; values: string[] }[] = [
// Filter to target Linux arch
{
name: "description",
values: ["*linux*", "*Linux*"],
},
// Filter to target EKS Nodes
{
name: "name",
values: ["amazon-eks-node-*"],
},
// Filter to target General, non-GPU image class
{
name: "manifest-location",
values: ["*amazon-eks-node*"],
},
// Filter to target architecture
{
name: "architecture",
values: ["x86_64"],
},
// Filter to target a specific k8s version
{
name: "description",
values: ["*k8s*" + v + "*"],
},
];

// `602401143452` is the ID assigned to `Amazon` and is required for AMIs that are hosted in AWS default regions
// `800184023465` is the owner ID of the creator of the EKS Optimized AMI in ap-east-1
// `558608220178` is the owner ID of the creator of the EKS Optimized AMI in me-south-1
// It is important to note that neither `800184023465` nor `558608220178` are assigned any IDs in default regions
// and `602401143452` is not assigned any AMIs in `ap-east-1` or `me-south-1` regions so this lookup is safe to make
// AWS Guide for EKS Optimized AMIs https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html
const eksWorkerAmiIds = aws.getAmiIds({
filters,
owners: ["602401143452", "800184023465", "558608220178"],
sortAscending: true,
}, { parent, async: true });

const bestAmiId = eksWorkerAmiIds.then(r => r.ids.pop()!);
if (!bestAmiId) {
throw new Error("No Linux AMI Id was found.");
}
return bestAmiId;
const parameterName = `/aws/service/eks/optimized-ami/${v}/${amiType}/recommended/image_id`;
return aws.ssm.getParameter({name: parameterName}).value;
});
// When we automatically pick an image to use, we want to ignore any changes to this later by default.
ignoreChanges = ["imageId"];
}

// Enable auto-assignment of public IP addresses on worker nodes for
Expand All @@ -468,7 +448,7 @@ ${customUserData}
deleteOnTermination: true,
},
userData: userdata,
}, { parent: parent, ignoreChanges: ignoreChanges });
}, { parent });

// Compute the worker node group subnets to use from the various approaches.
let workerSubnetIds: pulumi.Output<string[]>;
Expand Down

0 comments on commit 17dec48

Please sign in to comment.