Implement endpoint slice resolution for ate api connections for HA - #582
Implement endpoint slice resolution for ate api connections for HA#582Michael Aspinwall (michaelasp) wants to merge 1 commit into
Conversation
a8e119e to
9ecd49d
Compare
|
TLS error caused e2e to fail, changed the url to match. |
9ecd49d to
a104c05
Compare
|
Initial agent review:
Could the Kubernetes client requirement be made conditional/opt-in so only callers selecting Additional findings from the initial pass:
|
a104c05 to
8bbb12d
Compare
Ok I made it so that if we provide a kubernetes client we create a resolver. Although on the apiserver side of things, we used to set the keepalive in order to close connections to allow for us to pick up new endpoints, however that is not optimal. This PR removes that in order to prevent spurious connection drops. This change would make DNS clients not be able tell if new apiservers have come up until they restarted. Not sure if we should account for that. Julian Gutierrez Oschmann (@juli4n) made the change in order to add the keepalive, wdyt? |
What if we have 2 code paths:
|
The issue is that this is on 2 sides and we can have many clients to one server. The server can be configured with how long to keep the connection alive(default infinity) but was turned down to kill a connection every minute to allow dns based clients to find new replicas. This is bad for keeping a live connection, and was reported as an issue in GRPC, grpc/grpc#12295 The endpoint resolver fixes that but doesn't help if clients use the dns backend without the resolver. I think that we should expect that if clients connect with no resolver then they do not get the ability to dynamically obtain backends. Maybe we could create a MaxConnectionAge of something large, ~1 hr or so just to ensure that eventually those clients would obtain backends? |
8bbb12d to
a931a05
Compare
That sounds ok to me. But maybe stepping back a second what would be the typical way to solve something like this? |
6e861cd to
60ca9c6
Compare
This is mostly an issue that discovery of endpoints happens at the beginning of a connection instantiation with DNS and grpc creates a long lived connection that unless dropped will not reobtain endpoints. We could maybe also create a DNS resolver that obtains endpoints via polling or some other mechanism, but if we consider that most clients will be able to obtain native kubernetes endpoints then this should be enough to eventually balance out any non native client and allow for clients that do want/need immediate access to all endpoints the ability to do so. I added a hour connection drop so it should reconnect infrequently enough to not cause any issues for clients but allow for any DNS based client to ~eventually obtain IPs. |
Benjamin Elder (BenTheElder)
left a comment
There was a problem hiding this comment.
Thanks!
AI first pass with some minor issues:
|
Should also fix the CI / linter findings. |
60ca9c6 to
13e664d
Compare
| } | ||
| }) | ||
|
|
||
| update := func(_ any) { r.updateState() } |
There was a problem hiding this comment.
Maybe just:
reg, err := inf.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(_ any) { r.updateState() },
UpdateFunc: func(_, _ any) { r.updateState() },
DeleteFunc: func(_ any) { r.updateState() },
}
There is no much value in the update wrapper as UpdateFunc needs to also inline the closure.
There was a problem hiding this comment.
Done! Also added an error check here, that might have been bad.
13e664d to
d90e940
Compare
| selector: selector, | ||
| } | ||
|
|
||
| _ = inf.Informer().SetWatchErrorHandler(func(_ *cache.Reflector, err error) { |
There was a problem hiding this comment.
🤖 nit 🟢 – Installing a handler here replaces client-go's default one, which was the thing logging "failed to list/watch". Watch errors now reach only cc.ReportError, so they surface through failing RPCs and nowhere else — an idle ClientConn produces no operator-visible signal at all, which is the case where a missing-RBAC misconfiguration is easiest to miss. A slog.Error alongside the ReportError keeps both.
There was a problem hiding this comment.
Ah good catch, made it so this logs an error as well. Thanks!
d90e940 to
5b7e4f7
Compare
Fixes #565
Replaces standard DNS resolution (
dns:///) and the forced 1-minuteMaxConnectionAgereconnect workaround with a native, event-driven Kubernetes gRPC resolver (internal/k8sresolver). The resolver uses client-go'sSharedInformerFactoryandEndpointSliceListerto watchdiscoveryv1.EndpointSliceresources in real time.Verification
Created a kind cluster to test changes by scaling the deployments up and down and verified the new servers were connected to by clients.
1. Kind Cluster Scale-Out & EndpointSlice Discovery
Click to view kubectl scale and EndpointSlice output
$ kubectl scale deployment/ate-api-server -n ate-system --replicas=4
deployment.apps/ate-api-server scaled
2. Proof of Active gRPC Load-Balancing Across All Replicas