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: construct library for ECS #1041

Closed
wants to merge 113 commits into from
Closed

feat: construct library for ECS #1041

wants to merge 113 commits into from

Conversation

rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented Oct 30, 2018

Add an initial version of a construct library for AWS Elastic Container Service.

This construct library isn't fully feature-complete yet. This is the first iteration so
that people can use it for experimentation and put it to the test, and we can improve
on it later.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

SoManyHs and others added 30 commits September 28, 2018 11:42
- Fix linting errors
- VPC is now an argument and not created inside the cluster
- Link the AutoScalingGroup up to the cluster via userData
- Give the ASG instance role the required IAM permissions
- Extend ECS-optimized AMI table with all regions
- Add an example configuration option to deny containers
  access to EC2 instance metadata service.
Was getting error:
lib/index.ts(7,1): error TS2308: Module './cluster' has already exported
a member named 'ClusterName'. Consider explicitly re-exporting to
resolve the ambiguity.
lib/index.ts(7,1): error TS2308: Module './task-definition' has already
exported a member named 'TaskDefinitionArn'. Consider explicitly
re-exporting to resolve the ambiguity.

This seemed to make npm run build happy
@rix0rrr rix0rrr self-assigned this Oct 30, 2018
{
"app": "node index",
"context": {
"availability-zones:585695036304:us-east-1": [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it normal practice in the CDK to check in account IDs? Normally we avoid publicly sharing account IDs...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. We should definitely delete

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this should not have been checked in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect customers to check this in to their repos, or should cdk.json generally be git'ignored? Should cdk init add that to a .gitignore file? Sounds like we need a separate issue to track that

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi this stuff is online for all to see

Copy link
Member

@clareliguori clareliguori left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! Looking good, not much jumped out at me that has to be changed before merging. Most of my comments can be addressed in follow-up PRs

@@ -0,0 +1,3 @@
{
"app": "../node_modules/.bin/cdk-applet-js fargate-service.yml"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I get this magical cdk-applet-js file, because it is not appearing for me locally even after a build

packages/@aws-cdk/aws-ecs/README.md Show resolved Hide resolved
packages/@aws-cdk/aws-ecs/README.md Show resolved Hide resolved
packages/@aws-cdk/aws-ecs/README.md Show resolved Hide resolved
/**
* Time after startup to ignore unhealthy load balancer checks.
*
* @default ??? FIXME
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nathanpeck any guidance here on a sane default?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should maybe be removed from the service properties and only added if the customer specifies a loadBalancer.

/**
* Called when the image is used by a ContainerDefinition
*/
public abstract bind(containerDefinition: ContainerDefinition): void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the value of this method? It doesn't actually seem to bind to this specific image object; it just sets a flag back in the containerDefinition?

this.securityGroup = autoScalingGroup.connections.securityGroup!;

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so niiiiiiice

if (!props.containersAccessInstanceRole) {
// 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');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For awsvpc mode (which doesn't use docker0), you should also set ECS_AWSVPC_BLOCK_IMDS=true
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html

"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
).addAllResources()); // Conceivably we might do better than all resources and add targeted ARNs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on the comment


```ts
// Create an ECS cluster (backed by an AutoScaling group)
const cluster = new ecs.EcsCluster(this, 'Cluster', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need two separate constructs for ecs.EcsCluster and ecs.FargateCluster? I think this introduces some naming complexity (especially later down the line when we have Fargate for EKS). By having them so separate, it also hides the fact that customers can (and do) have mixed-mode clusters with some EC2 and some Fargate mode tasks.

The only real difference is how many instances (if any) are configured. Why not have a single new ecs.Cluster() construct, that accepts an optional instanceConfiguration prop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's true that we wanted to supported mixed-mode clusters, these are an extremely low percentage of customers. We wanted the construct library to provide a more opinionated way to set up infrastructure. In addition provisioning capacity in an ECS cluster, there is some differences in the networking setup as well.

Unless you know of good reasons why customers wouldn't want to have a homogeneous cluster, keeping separate cluster types seemed to streamline the design of other ECS constructs.

const cluster = new ecs.EcsCluster(this, 'Cluster', {
vpc,
size: 3,
instanceType: new InstanceType("t2.xlarge")
Copy link
Contributor

@PaulMaddox PaulMaddox Oct 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instanceCount is more descriptive than size.

I also think this API for just specifying instance type and count is too simplistic, and limits future options. For example, one nice thing we could do as a TODO is allow people to specify multiple instance types, and whether they want to use spot etc. The ECS L2 construct could then abstract away a lot of the complexity of creating this kind of diverse-bidding-strategy setup.

As above, I'd favour an instanceConfiguration type prop that could allow expressing more advanced configurations. We could then provide some sane-default examples of instance configurations that people could drop-in, or they could create their own.


- Use the `EcsCluster`, `EcsTaskDefinition` and `EcsService` constructs to
run tasks on EC2 instances running in your account.
- Use the `FargateCluster`, `FargateTaskDefinition` and `FargateService`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, is this naming future-proof/correct? EcsService vs FargateService is slightly confusing as both run on ECS. Maybe ecs.EC2Service and ecs.FargateService?

## Service

A `Service` instantiates a `TaskDefinition` on a `Cluster` a given number of
times, optionally associating them with a load balnacer. Tasks that fail will
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/load balnacer/load balancer/

Task AutoScaling is powered by *Application AutoScaling*. Refer to that for
more information.

## Instance AutoScaling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting up instance-autoscaling with proper draining (via lifecycle hook+lambda) is exactly the sort of undifferentiated heavy lifting that an L2 construct should be doing. From speaking to customers previously, reserved memory is normally a pretty sane default to scale on. For a drop-in example of the ASG hook/lambda function for draining, see https://github.com/aws-samples/ecs-refarch-cloudformation/blob/master/infrastructure/lifecyclehook.yaml

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, that is potentially more complicated than I had expected. Might hit you up next week as I'm trying to implement this.

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Oct 31, 2018

Closing in favor of newer one

@rix0rrr rix0rrr closed this Oct 31, 2018
@NGL321 NGL321 added the contribution/core This is a PR that came from AWS. label Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants