-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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): allow load balancing to any container and port of service #4107
Conversation
Thanks so much for taking the time to contribute to the AWS CDK ❤️ We will shortly assign someone to review this pull request and help get it
|
@karlpatr please review. |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is much cleaner than my own first attempt, which I'll be closing in favor of this code. I look forward to seeing it published so I can adopt my project code.
@@ -232,6 +295,66 @@ export abstract class BaseService extends Resource | |||
return ret; | |||
} | |||
|
|||
public loadBalancerTarget(options: LoadBalancerTargetOptions): IEcsLoadBalancerTarget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming doc comments are a next step after these reviews, but it will be important to highlight how this factory function is used since it's not a common CDK pattern (from what I can tell)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this docstring needs a rewrite. Some things I want to highlight:
This method is called to register the
It doesn't have a side effect, so I wouldn't phrase it like this.
Don't call this function alone.
Avoid using negatives. Tell me what I should be doing instead!
Suggested phrasing:
Return a load balancing target for a specific container and port
Use this function to create a load balancer target if you want to load balance to
another container than the first essential container or the first mapped port on
the container.
Use the return value of this function where you would normally use a load balancer
target, instead of the `Service` object itself.
@example
listener.addTarget(service.loadBalancerTarget({
containerName: 'MyContainer',
containerPort: 1234
}));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very helpful feedback. Thanks!
}; | ||
} | ||
|
||
public registerContainerTargets(containers: TargetProps[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this is implemented in terms loadBalancerTarget
; that's a good thing for maintenance and answers my earlier concerns about feature parity, but again leaves me wondering if 2 different interfaces is a boon in practice if I'm trying to discover how to use the system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm not sure why we need to invert the call pattern here. Why is the current mechanism of targetGroup.addTarget()
not good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using registerContainerTargets
we could potentially make some setting (e.g., target group port) opinionated so that users don't need to set up some properties. Also this is a team decision and we feel like it would make more senses for some users to start from service
instead of listener
or target group
. However, we might be wrong since we aren't real users. I agree that this implementation needs some tweaks, if we decide to keep it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you be open to separating the concerns?
As in, add the fine-grained target control in this PR, and add the convenience function in a future PR? I would like to separate them out very cleanly.
If you insist on adding it, what I would like to do is mark the function and every new interface that is used to support it @experimental
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am more inclined to put it in another PR so that I can invite my teammate to review and help refine the implementation, because we feel like this is a behavior we should support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe it's also worthwhile to reimplement the default attachToApplicationLoadBalancer()
as such to make sure we converge to a single code path as quickly as possible:
class BaseService {
public attachToApplictionLoadBalancer(args: Args) {
return this.defaultLoadBalancerTarget.attachToApplicationLoadBalancer(args);
}
private get defaultLoadBalancerTarget() {
return this.loadBalancerTarget({
containerName: this.taskDefinition.defaultContainer!.containerName,
containerPort: this.taskDefinition.defaultContainer!.containerPort,
});
}
}
Put into the docstring of XxxService
that if it is used as a load balancer target, it will route to the default port of the default container, and that people should use loadBalancerTarget()
to route traffic somewhere else.
Don't forget to describe this in README.md
as well, and give an example of the new usage.
}; | ||
} | ||
|
||
public registerContainerTargets(containers: TargetProps[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm not sure why we need to invert the call pattern here. Why is the current mechanism of targetGroup.addTarget()
not good enough?
}; | ||
} | ||
|
||
if (this.networkMode === NetworkMode.BRIDGE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the order of if
s here correct? Do we really check port mappings before checking network mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I fully understand what you mean. Is there any problem with the logic: check if port mapping exists then determine the security group port to open?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user somehow specifies a host port in bridge mode (and this is a public function so they could call it directly with too much information) I believe the early return would cause an incorrect binding to that port instead of the ephemeral range. Moving this above the port check would fix that edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the user specifies a host port in bridge mode, it should return the host port right? I think it returns the ephemeral range only if the network mode is bridge and the host port is 0 (or undefined). See hostPort.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, disregard this one :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just trying to be sure. This looks and feels like hairy logic.
495912b
to
f498e8d
Compare
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it. Almost there, just some small niggles.
@@ -232,6 +295,66 @@ export abstract class BaseService extends Resource | |||
return ret; | |||
} | |||
|
|||
public loadBalancerTarget(options: LoadBalancerTargetOptions): IEcsLoadBalancerTarget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this docstring needs a rewrite. Some things I want to highlight:
This method is called to register the
It doesn't have a side effect, so I wouldn't phrase it like this.
Don't call this function alone.
Avoid using negatives. Tell me what I should be doing instead!
Suggested phrasing:
Return a load balancing target for a specific container and port
Use this function to create a load balancer target if you want to load balance to
another container than the first essential container or the first mapped port on
the container.
Use the return value of this function where you would normally use a load balancer
target, instead of the `Service` object itself.
@example
listener.addTarget(service.loadBalancerTarget({
containerName: 'MyContainer',
containerPort: 1234
}));
}; | ||
} | ||
|
||
public registerContainerTargets(containers: TargetProps[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you be open to separating the concerns?
As in, add the fine-grained target control in this PR, and add the convenience function in a future PR? I would like to separate them out very cleanly.
If you insist on adding it, what I would like to do is mark the function and every new interface that is used to support it @experimental
.
7e108fd
to
e6c97ad
Compare
e6c97ad
to
5e4135e
Compare
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
…4107) Add a `loadBalancerTarget()` method to ECS's Service, which allows load balancing to containers other than the default container and to ports beside the first mapped port. Services can be registered to multiple ELBv2 target groups at the same time if necessary.
Add a
loadBalancerTarget()
method to ECS's Service, which allows load balancingto containers other than the default container and to ports beside the first mapped port.
Services can be registered to multiple ELBv2 target groups at the same time if necessary.
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license