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
add global rate limiting support #3298
Conversation
cd3cc9d
to
f5fe2ca
Compare
Codecov Report
@@ Coverage Diff @@
## main #3298 +/- ##
==========================================
+ Coverage 75.54% 75.77% +0.22%
==========================================
Files 98 98
Lines 6417 6535 +118
==========================================
+ Hits 4848 4952 +104
- Misses 1460 1475 +15
+ Partials 109 108 -1
|
5131308
to
dc96013
Compare
@stevesloka @youngnick @sunjayBhatia I'd appreciate an initial review on this. I am still working on documentation. |
9cdc0ea
to
f535ccf
Compare
f535ccf
to
eb79b61
Compare
Ran through a full test of the guide, fixed a couple small things. |
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.
Looks good overall! Lots of changes but you're right mostly generated etc.
Just a couple small comments
pkg/config/parameters.go
Outdated
Domain string `yaml:"domain,omitempty"` | ||
|
||
// FailOpen defines whether to allow requests to proceed when the | ||
// Rate Limit Service fails to respond properly. |
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.
nit: Maybe define properly? (timeout etc.)
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.
👍 also reminds me I forgot to add to site/docs/main/configuration.md
and the example config file, will do that as well.
internal/xdscache/v3/listener.go
Outdated
AllowChunkedLength(v.ListenerConfig.AllowChunkedLength). | ||
NumTrustedHops(v.ListenerConfig.XffNumTrustedHops) | ||
|
||
if rlc := v.RateLimitConfig; rlc != nil { |
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.
nit: Could this be collapsed so we don't need to add the if (here and above)?
e.g. envoy_v3.GlobalRateLimitFilter
could take just a RateLimitConfig
and do the nil
check there? and builder.AddFilter
does nothing if it gets nil
?
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 good idea, that'd clean this up; though as-is that would create an import cycle so need to re-jigger things a bit.
@@ -294,6 +296,36 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error { | |||
XffNumTrustedHops: ctx.Config.Network.XffNumTrustedHops, | |||
} | |||
|
|||
if ctx.Config.RateLimitService.ExtensionService != "" { | |||
namespacedName := k8s.NamespacedNameFrom(ctx.Config.RateLimitService.ExtensionService) |
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 it make sense to pull this sort of logic (fetching a service/checking for existence/getting some spec params) into a common helper? I'm thinking this logic could possibly be duplicated elsewhere?
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.
The existing extension service code gets its ExtensionService
via the DAG cache, so it's a different code path / not really duplicated with this logic. Maybe we can keep an eye on this for refactoring when we add our next extension service impl.
eb79b61
to
883f443
Compare
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.
Overall looks great to me @skriss! Just a couple questions / thoughts.
// ensure the specified ExtensionService exists | ||
res, err := client.Get(context.Background(), namespacedName.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
return fmt.Errorf("error getting rate limit extension service %s: %v", namespacedName, err) |
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.
Should this be a fatal error or not configure rate limiting until the extension service exists?
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.
Agree it's not ideal to require the extension service to exist at startup. I think we could change the flow somewhat to resolve the extension service ref during the DAG build instead. If it's OK with you, I'll file a follow-up issue to look at that?
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.
yup sure thing!
@@ -99,3 +99,7 @@ data: | |||
# Configure the number of additional ingress proxy hops from the | |||
# right side of the x-forwarded-for HTTP header to trust. | |||
# num-trusted-hops: 0 | |||
# rateLimitService: | |||
# extensionService: projectcontour/ratelimit |
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.
We have comments for other bits in this config explaining what they mean, maybe match that a bit?
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.
added
@@ -0,0 +1,11 @@ | |||
apiVersion: v1 |
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 we should include this or just reference what to setup. I guess it's a nice copy/paste way to follow a guide so probably good.
|
||
## Deploy an RLS | ||
|
||
For this guide, we'll deploy the [Envoy rate limit service][4] as our RLS. |
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.
Maybe just give a couple more sentences on how the RLS works just so it's clear what is happening? (i.e. The RLS uses a Redis cache internally. Blah blah?)
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.
copied an excerpt from the Envoy RLS README to give some more color.
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.
LGTM, nice work.
// ensure the specified ExtensionService exists | ||
res, err := client.Get(context.Background(), namespacedName.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
return fmt.Errorf("error getting rate limit extension service %s: %v", namespacedName, err) |
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 this is not fatal, then we need instead to do this similarly to the Envoy service status watcher - a separate goroutine that looks for the defined ExtensionService and sets up the config once it exists and is working.
I'd say that's quite a bit of extra work for minimal gain. If you're configuring the feature, you should have access to restart Contour, and you should be able to ensure everything is set up correctly.
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.
See #3298 (comment), I think we could make some improvements here but I'm not considering it blocking.
883f443
to
465536c
Compare
07a9a10
to
5036185
Compare
I believe I've addressed everyone's review comments now, please take another look! |
5036185
to
ae633ba
Compare
Adds support for configuring an external Rate Limit Service (RLS) that is used for making global rate limit decisions. Adds support to HTTPProxy for global rate limit policies, that generate descriptors for requests to be sent to the RLS for rate-limit decisions. Closes projectcontour#370. Signed-off-by: Steve Kriss <krisss@vmware.com>
Signed-off-by: Steve Kriss <krisss@vmware.com>
Signed-off-by: Steve Kriss <krisss@vmware.com>
Signed-off-by: Steve Kriss <krisss@vmware.com>
ae633ba
to
fc921c6
Compare
😅 |
Adds support for configuring an external Rate Limit Service (RLS) that is used for making global rate limit decisions. Adds support to HTTPProxy for global rate limit policies, that generate descriptors for requests to be sent to the RLS for rate-limit decisions. Closes projectcontour#370. Signed-off-by: Steve Kriss <krisss@vmware.com> Signed-off-by: iyacontrol <gaohj2015@yeah.net>
Adds support for configuring an external Rate Limit
Service (RLS) that is used for making global rate
limit decisions. Adds support to HTTPProxy for
global rate limit policies, that generate descriptors
for requests to be sent to the RLS for rate-limit
decisions.
Closes #370.
Signed-off-by: Steve Kriss krisss@vmware.com