Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ecs): bottlerocket support #10097

Merged
merged 11 commits into from
Sep 2, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-ecs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,26 @@ cluster.addCapacity('AsgSpot', {
});
```

### Bottlerocket
pahud marked this conversation as resolved.
Show resolved Hide resolved

[Bottlerocket](https://aws.amazon.com/bottlerocket/) is a Linux-based open source operating system that is
purpose-built by AWS for running containers. You can launch Amazon ECS container instances with the Bottlerocket AMI.

> **NOTICE**: The Bottlerocket AMI is in developer preview release for Amazon ECS and is subject to change.

The following example will create a capacity with self-managed Amazon EC2 capacity of 2 `c5.large` Linux instances running with `Bottlerocket` AMI.

Note that you must specify either a `machineImage` or `machineImageType`, at least one, not both.


```ts
cluster.addCapacity('bottlerocket-asg', {
minCapacity: 2,
instanceType: new ec2.InstanceType('c5.large'),
machineImageType: ecs.MachineImageType.BOTTLEROCKET,
});
```

### SNS Topic Encryption

When the `ecs.AddCapacityOptions` that you provide has a non-zero `taskDrainTime` (the default) then an SNS topic and Lambda are created to ensure that the
Expand Down
118 changes: 104 additions & 14 deletions packages/@aws-cdk/aws-ecs/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ export interface ClusterProps {
readonly containerInsights?: boolean;
}

/**
* The machine image type
*/
export enum MachineImageType {
/**
* Amazon ECS-optimized Amazon Linux 2 AMI
*/
AMAZON_LINUX_2,
/**
* Bottlerocket AMI
*/
BOTTLEROCKET
}

/**
* A regional grouping of one or more container instances on which you can run tasks and services.
*/
Expand Down Expand Up @@ -171,15 +185,27 @@ export class Cluster extends Resource implements ICluster {
* Returns the AutoScalingGroup so you can add autoscaling settings to it.
*/
public addCapacity(id: string, options: AddCapacityOptions): autoscaling.AutoScalingGroup {
if (options.machineImage && options.machineImageType) {
throw new Error('You can only specify either a machineImage or machineImageType, not both.');
}

let machineImage: ec2.IMachineImage;

machineImage = options.machineImage ?? options.machineImageType === MachineImageType.BOTTLEROCKET ?
new BottleRocketImage() : new EcsOptimizedAmi();

const autoScalingGroup = new autoscaling.AutoScalingGroup(this, id, {
...options,
vpc: this.vpc,
machineImage: options.machineImage || new EcsOptimizedAmi(),
machineImage,
updateType: options.updateType || autoscaling.UpdateType.REPLACING_UPDATE,
instanceType: options.instanceType,
});

this.addAutoScalingGroup(autoScalingGroup, options);
this.addAutoScalingGroup(autoScalingGroup, {
machineImageType: options.machineImageType,
...options,
});

return autoScalingGroup;
}
Expand All @@ -196,19 +222,33 @@ export class Cluster extends Resource implements ICluster {
this.connections.connections.addSecurityGroup(...autoScalingGroup.connections.securityGroups);

// Tie instances to cluster
autoScalingGroup.addUserData(`echo ECS_CLUSTER=${this.clusterName} >> /etc/ecs/ecs.config`);

if (!options.canContainersAccessInstanceRole) {
// Deny containers access to instance metadata service
// Source: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html
autoScalingGroup.addUserData('sudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP');
autoScalingGroup.addUserData('sudo service iptables save');
// The following is only for AwsVpc networking mode, but doesn't hurt for the other modes.
autoScalingGroup.addUserData('echo ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config');
}
// Bottlerocket AMI
if (options.machineImageType===MachineImageType.BOTTLEROCKET) {
pahud marked this conversation as resolved.
Show resolved Hide resolved
autoScalingGroup.addUserData(
'[settings.ecs]',
`cluster = "${this.clusterName}"`,
pahud marked this conversation as resolved.
Show resolved Hide resolved
);
// Enabling SSM
// Source: https://github.com/bottlerocket-os/bottlerocket/blob/develop/QUICKSTART-ECS.md#enabling-ssm
autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
// required managed policy
autoScalingGroup.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonEC2ContainerServiceforEC2Role'));
iamhopaul123 marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Amazon ECS-optimized AMI for Amazon Linux 2
autoScalingGroup.addUserData(`echo ECS_CLUSTER=${this.clusterName} >> /etc/ecs/ecs.config`);

if (!options.canContainersAccessInstanceRole) {
// Deny containers access to instance metadata service
// Source: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html
autoScalingGroup.addUserData('sudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP');
autoScalingGroup.addUserData('sudo service iptables save');
// The following is only for AwsVpc networking mode, but doesn't hurt for the other modes.
autoScalingGroup.addUserData('echo ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config');
}

if (autoScalingGroup.spotPrice && options.spotInstanceDraining) {
autoScalingGroup.addUserData('echo ECS_ENABLE_SPOT_INSTANCE_DRAINING=true >> /etc/ecs/ecs.config');
if (autoScalingGroup.spotPrice && options.spotInstanceDraining) {
autoScalingGroup.addUserData('echo ECS_ENABLE_SPOT_INSTANCE_DRAINING=true >> /etc/ecs/ecs.config');
}
}

// ECS instances must be able to do these things
Expand Down Expand Up @@ -487,6 +527,41 @@ export class EcsOptimizedImage implements ec2.IMachineImage {
}
}

/**
* Construct an Bottlerocket image from the latest AMI published in SSM
*/
class BottleRocketImage implements ec2.IMachineImage {
private readonly amiParameterName: string;
/**
* Bottlerocket AMI variant
* @default - `aws-ecs-1`
*/
private readonly variant?: string;

/**
* Constructs a new instance of the BottleRocketImage class.
*/
public constructor() {
// only `aws-ecs-1` is currently available
this.variant = 'aws-ecs-1';

// set the SSM parameter name
this.amiParameterName = `/aws/service/bottlerocket/${this.variant}/x86_64/latest/image_id`;
}

/**
* Return the correct image
*/
public getImage(scope: Construct): ec2.MachineImageConfig {
const ami = ssm.StringParameter.valueForStringParameter(scope, this.amiParameterName);
return {
imageId: ami,
osType: ec2.OperatingSystemType.LINUX,
userData: ec2.UserData.custom(''),
};
}
}

/**
* A regional grouping of one or more container instances on which you can run tasks and services.
*/
Expand Down Expand Up @@ -678,6 +753,13 @@ export interface AddAutoScalingGroupCapacityOptions {
* @default The SNS Topic will not be encrypted.
*/
readonly topicEncryptionKey?: kms.IKey;

/**
* Specify the machine image type.
*
* @default MachineImageType.AMAZON_LINUX_2
*/
readonly machineImageType?: MachineImageType;
}

/**
Expand All @@ -689,9 +771,17 @@ export interface AddCapacityOptions extends AddAutoScalingGroupCapacityOptions,
*/
readonly instanceType: ec2.InstanceType;

/**
* Machine image type. Ignored if `machineImage` is defined.
*
* @default MachineImageType.AMAZON_LINUX_2
*/
readonly machineImageType?: MachineImageType;
pahud marked this conversation as resolved.
Show resolved Hide resolved

/**
* The ECS-optimized AMI variant to use. For more information, see
* [Amazon ECS-optimized AMIs](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html).
* Ignored if `MachineImageType` is defined.
pahud marked this conversation as resolved.
Show resolved Hide resolved
*
* @default - Amazon Linux 2
*/
Expand Down
Loading