Make leader election a top level pilot component, use it for singleton components#20809
Conversation
nmittler
left a comment
There was a problem hiding this comment.
was there previous leader election code in Istio? I was expecting to see moves/deletes
|
Yes, you can see it moved in |
There was a problem hiding this comment.
Is there any chance of losing the lock without shutting down? Is this what line 100 below is referring to?
There was a problem hiding this comment.
There is - at the very least if someone took away our rbac permission for config map, api server went down, etc we would. In this case, the context will be canceled, so the functions will stop (the library does this, not us).
I was confused looking at this original since I thought we just did nothing when we lose the lock, but its already handled. Probably warrants a comment.
The L100 comment is just for if WE explicitly cancel the context, we also drop the lock immediately. This allows another instance to take over immediately when we exit
nmittler
left a comment
There was a problem hiding this comment.
looks good overall ... took a first pass.
There was a problem hiding this comment.
I assume this will only be called before it's Run? If so, maybe we should just have a separate builder. Then we could do something like:
le := leaderelection.NewBuilder().
Namespace(ns).
Name(name).
Client(client).
WithRun(runFn1).
WithRun(runFn2).
Build()
...
le.Run(...)There was a problem hiding this comment.
@howardjohn there are a few options here:
- lock access to the
runFnsarray wherever it's used - Use a separate builder so that the API makes it clear that
runFnscan not be mutated after start. - Use a separate
Configobject that you pass toNew...and this is the thing that you build up before you create the elector.
Personally, I think my preference is 3, it's probably the simplest since you could just have a simple struct with no additional methods, like a builder would require. It also makes the New method clean.
Also, this method should probably be renamed to something like RunWhenLeader.
There was a problem hiding this comment.
Any reason to use a stop channel as opposed to context.Context? Seems like it would simplify the cancel code below.
There was a problem hiding this comment.
All of pilot is doing the stop channel passing. So at some point, we will need to convert stop channel into context? So I think its reasonable to do here rather than outside this function?
I feel like there should be a simpler way though..
There was a problem hiding this comment.
Make this a constant at the top?
Also, does this name need to be different for each component (e.g. webhook vs ingress)?
There was a problem hiding this comment.
No, we will have a single leader election for all components. Technically we could split it up, but I see no reason to have 4+ locks when we can have one?
There was a problem hiding this comment.
also I moved to a constant
|
/retest |
hzxuzhonghu
left a comment
There was a problem hiding this comment.
Mostly i am concerned when leader lost, will it renew?
pilot/pkg/bootstrap/options.go
Outdated
There was a problem hiding this comment.
by default hostname equals podname.
There was a problem hiding this comment.
@howardjohn looks like you're just using pod name for Identity in the election config? What are the requirements for this identity? Does it have to be a pod name?
|
I think it will renew but I will check the library |
|
Neither Istio's current implementation nor nginx-ingress do anything special to handle leader being lost: https://github.com/nginxinc/kubernetes-ingress/blob/5d4c5ddc70c2a40e78c803d0000908bfb2e6b63f/internal/k8s/controller.go#L310. So based on this I assume we have nothing to worry about here? |
|
also looked at the code, it basically does so if we lose it we can get it back again |
|
I remember in kube-controller-manager, the OnStoppedLeading is set to panic and exit. |
|
But for us we do nothing for OnStoppedLeading, so I don't think there is an issue? |
|
We do nothing just print a log. But this goroutine will exit. There is no way to re-acquire the lock. |
|
@hzxuzhonghu thanks for pushing back on this, i misunderstood the code. I simulated loosing the lock (by removing RBAC permission) and found
So I think you are right, we need some looping to acquire leadership again |
|
/hold I added a test that fails due to the k8s crashing bug |
4163c65 to
df198c2
Compare
df198c2 to
c3ceabd
Compare
4801164 to
be71e58
Compare
pilot/pkg/bootstrap/server.go
Outdated
275bf86 to
a745085
Compare
pilot/pkg/bootstrap/options.go
Outdated
There was a problem hiding this comment.
@howardjohn looks like you're just using pod name for Identity in the election config? What are the requirements for this identity? Does it have to be a pod name?
There was a problem hiding this comment.
@howardjohn there are a few options here:
- lock access to the
runFnsarray wherever it's used - Use a separate builder so that the API makes it clear that
runFnscan not be mutated after start. - Use a separate
Configobject that you pass toNew...and this is the thing that you build up before you create the elector.
Personally, I think my preference is 3, it's probably the simplest since you could just have a simple struct with no additional methods, like a builder would require. It also makes the New method clean.
Also, this method should probably be renamed to something like RunWhenLeader.
There was a problem hiding this comment.
nit: the name creates a stutter with the package name leaderelection.LeaderElection. Also, I think Elector is a little better than Election. Perhaps the package could be leader and the type could be Elector, so that callsites would see leader.Elector? WDYT?
|
In response to a cherrypick label: new pull request created: #20939 |
…n components (istio#20809) * Add initial leader election * Cleanup * Add unit tests * user leader election for ns controller, validation controller * Log about ingress * Add graceful shutdown * Fix tests, add injector controller * Fix lint * Add renewal when lease is droppped, failing test * wip * Get everything working * Fix build * lint
This PR does a few things, which I attempted to decompose into different commits