Skip to content

Commit

Permalink
feat: Windows fast launch (#521)
Browse files Browse the repository at this point in the history
Add an option for enabling [fast launch](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-ami-config-fast-launch.html) for Windows AMIs. This should speed up booting up of EC2 Windows runners.

Note that it does come with [extra cost](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-fast-launch-manage-costs.html).

```typescript
const ec2WindowsImageBuilder = Ec2RunnerProvider.imageBuilder(stack, 'Windows EC2 Builder', {
  os: Os.WINDOWS,
  vpc,
  awsImageBuilderOptions: {
    fastLaunchOptions: {
      enabled: true,
    },
  },
});
const runners = new GitHubRunners(stack, 'runners', {
  providers: [
    new Ec2RunnerProvider(stack, 'Fast Windows', {
      labels: ['windows'],
      imageBuilder: ec2WindowsImageBuilder,
    }),
  ],
}
```

Before:
<img width="69" alt="image" src="https://github.com/CloudSnorkel/cdk-github-runners/assets/1156773/f92a363e-9892-430a-9511-f70800909fe0">

After:
<img width="74" alt="image" src="https://github.com/CloudSnorkel/cdk-github-runners/assets/1156773/d7da163c-4f82-4cbb-9b48-bfb1e8da3850">

Resolves #466
Closes #514
  • Loading branch information
kichik committed Mar 27, 2024
1 parent 7f970ea commit 319b011
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 10 deletions.
83 changes: 83 additions & 0 deletions API.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

120 changes: 115 additions & 5 deletions src/image-builders/aws-image-builder/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,48 @@ export interface AwsImageBuilderRunnerImageBuilderProps {
* @default m5.large
*/
readonly instanceType?: ec2.InstanceType;

/**
* Options for fast launch.
*
* This is only supported for Windows AMIs.
*
* @default disabled
*/
readonly fastLaunchOptions?: FastLaunchOptions;
}

/**
* Options for fast launch.
*/
export interface FastLaunchOptions {
/**
* Enable fast launch for AMIs generated by this builder. It creates a snapshot of the root volume and uses it to launch new instances faster.
*
* This is only supported for Windows AMIs.
*
* @note this feature comes with additional resource costs. See the documentation for more details. https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-fast-launch-manage-costs.html
* @note enabling fast launch on an existing builder will not enable it for existing AMIs. It will only affect new AMIs. If you want immediate effect, trigger a new image build. Alternatively, you can create a new builder with fast launch enabled and use it for new AMIs.
*
* @default false
*/
readonly enabled?: boolean;

/**
* The maximum number of parallel instances that are launched for creating resources.
*
* Must be at least 6.
*
* @default 6
*/
readonly maxParallelLaunches?: number;

/**
* The number of pre-provisioned snapshots to keep on hand for a fast-launch enabled Windows AMI.
*
* @default 1
*/
readonly targetResourceCount?: number;
}

/**
Expand Down Expand Up @@ -266,6 +308,7 @@ export class AwsImageBuilderRunnerImageBuilder extends RunnerImageBuilderBase {
private readonly instanceType: ec2.InstanceType;
private infrastructure: imagebuilder.CfnInfrastructureConfiguration | undefined;
private readonly role: iam.Role;
private readonly fastLaunchOptions?: FastLaunchOptions;

constructor(scope: Construct, id: string, props?: RunnerImageBuilderProps) {
super(scope, id, props);
Expand All @@ -285,6 +328,7 @@ export class AwsImageBuilderRunnerImageBuilder extends RunnerImageBuilderBase {
this.baseImage = props?.baseDockerImage ?? defaultBaseDockerImage(this.os);
this.baseAmi = props?.baseAmi ?? defaultBaseAmi(this, this.os, this.architecture);
this.instanceType = props?.awsImageBuilderOptions?.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE);
this.fastLaunchOptions = props?.awsImageBuilderOptions?.fastLaunchOptions;

// confirm instance type
if (!this.architecture.instanceTypeMatch(this.instanceType)) {
Expand Down Expand Up @@ -587,6 +631,75 @@ export class AwsImageBuilderRunnerImageBuilder extends RunnerImageBuilderBase {
requireImdsv2: true,
});

const launchTemplateConfigs: imagebuilder.CfnDistributionConfiguration.LaunchTemplateConfigurationProperty[] = [{
launchTemplateId: launchTemplate.launchTemplateId,
setDefaultVersion: true,
}];
const fastLaunchConfigs: imagebuilder.CfnDistributionConfiguration.FastLaunchConfigurationProperty[] = [];

if (this.fastLaunchOptions?.enabled ?? false) {
if (!this.os.is(Os.WINDOWS)) {
throw new Error('Fast launch is only supported for Windows');
}

// create a separate launch template for fast launch so:
// - settings don't affect the runners
// - enabling fast launch on an existing builder works (without a new launch template, EC2 Image Builder will use the first version of the launch template, which doesn't have instance or VPC config)
// - setting vpc + subnet on the main launch template will cause RunInstances to fail
// - EC2 Image Builder seems to get confused with which launch template version to base any new version on, so a new template is always best
const fastLaunchTemplate = new ec2.CfnLaunchTemplate(this, 'Fast Launch Template', {
launchTemplateData: {
metadataOptions: {
httpTokens: 'required',
},
instanceType: this.instanceType.toString(),
networkInterfaces: [{
subnetId: this.vpc?.selectSubnets(this.subnetSelection).subnetIds[0],
deviceIndex: 0,
groups: this.securityGroups.map(sg => sg.securityGroupId),
}],
tagSpecifications: [
{
resourceType: 'instance',
tags: [{
key: 'Name',
value: `${this.node.path}/Fast Launch Instance`,
}],
},
{
resourceType: 'volume',
tags: [{
key: 'Name',
value: `${this.node.path}/Fast Launch Instance`,
}],
},
],
},
tagSpecifications: [{
resourceType: 'launch-template',
tags: [{
key: 'Name',
value: `${this.node.path}/Fast Launch Template`,
}],
}],
});

launchTemplateConfigs.push({
launchTemplateId: fastLaunchTemplate.attrLaunchTemplateId,
setDefaultVersion: true,
});
fastLaunchConfigs.push({
enabled: true,
launchTemplate: {
launchTemplateId: fastLaunchTemplate.attrLaunchTemplateId,
},
maxParallelLaunches: this.fastLaunchOptions?.maxParallelLaunches ?? 6,
snapshotConfiguration: {
targetResourceCount: this.fastLaunchOptions?.targetResourceCount ?? 1,
},
});
}

const stackName = cdk.Stack.of(this).stackName;
const builderName = this.node.path;

Expand All @@ -608,11 +721,8 @@ export class AwsImageBuilderRunnerImageBuilder extends RunnerImageBuilderBase {
'GitHubRunners:Builder': builderName,
},
},
launchTemplateConfigurations: [
{
launchTemplateId: launchTemplate.launchTemplateId,
},
],
launchTemplateConfigurations: launchTemplateConfigs,
fastLaunchConfigurations: fastLaunchConfigs.length > 0 ? fastLaunchConfigs : undefined,
},
],
});
Expand Down
4 changes: 2 additions & 2 deletions test/default.integ.snapshot/github-runners-test.assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,15 +235,15 @@
}
}
},
"2aae55820f5b3b1bc6c23108a950d448c9f06303c2e15a71f6aed05080984ca5": {
"c778a1355556a7931c74bf18556e58cfff5dd5111b4157913931d869afcf4877": {
"source": {
"path": "github-runners-test.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "2aae55820f5b3b1bc6c23108a950d448c9f06303c2e15a71f6aed05080984ca5.json",
"objectKey": "c778a1355556a7931c74bf18556e58cfff5dd5111b4157913931d869afcf4877.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
9 changes: 6 additions & 3 deletions test/default.integ.snapshot/github-runners-test.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -3405,7 +3405,8 @@
{
"LaunchTemplateId": {
"Ref": "AMILinuxBuilderLaunchtemplateA29452C4"
}
},
"SetDefaultVersion": true
}
],
"Region": {
Expand Down Expand Up @@ -6416,7 +6417,8 @@
{
"LaunchTemplateId": {
"Ref": "AMILinuxarm64BuilderLaunchtemplate8F5EFF44"
}
},
"SetDefaultVersion": true
}
],
"Region": {
Expand Down Expand Up @@ -7529,7 +7531,8 @@
{
"LaunchTemplateId": {
"Ref": "WindowsEC2BuilderLaunchtemplate0A66E9C2"
}
},
"SetDefaultVersion": true
}
],
"Region": {
Expand Down

0 comments on commit 319b011

Please sign in to comment.