-
Notifications
You must be signed in to change notification settings - Fork 114
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
Refactor node draining racing avoid condition #130
Conversation
}, 3*time.Second, 3, true, ctx.Done()) | ||
|
||
done := make(chan bool) | ||
go dn.getDrainLock(ctx, done) |
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.
Can we run dn.getDrainLock
in foreground and not use done
chan?
I assume leaderelection.RunOrDie
is a loop w/o timeout, is it true?
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 leaderelection.RunOrDie
runs forever unless the context is canceled. I didn't run it in the foreground, because I want it keeps leading until the node finishes draining. So the rest nodes can only start the election after the prior one finishes draining if there is no reboot required.
pkg/daemon/daemon.go
Outdated
@@ -18,6 +18,14 @@ import ( | |||
"time" | |||
|
|||
"github.com/golang/glog" | |||
sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/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.
nit: could you separate local imports from external imports
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.
This was updated by some plugin of my editor automatically. I'll change it back.
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.
fixed
} | ||
|
||
// start the leader election | ||
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ |
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.
looking at leaderelection docs:
Package leaderelection implements leader election of a set of endpoints. It uses an annotation in the endpoints object to store the record of the election state. This implementation does not guarantee that only one client is acting as a leader (a.k.a. fencing).
is it not an issue ? i think what we are doing here is considered fencing
how will the system behave when there is only one endpoint trying to take the lead on LeaseLock ?
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.
Instead of using endpoint, I use Lease API for leader election here. I don't think that statement applies. As all the clients race for the same Lease object. So I don't think there could be more than one acting as leader.
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.
OK thanks for explaining
time.Sleep(1 * time.Second) | ||
if dn.drainable { | ||
glog.V(2).Info("drainNode(): no other node is draining") | ||
err = dn.annotateNode(dn.name, annoDraining) |
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 this mechanism, do we still need to annotate the node with annotDraining
?
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.
That is the trick. The leader election mechanism requires the leader to keep updating the Lease object. But in our case, the node may reboot itself, then lose leadership. So I use a 2 layers lock here. The node can only start draining with 2 conditions: 1) it becomes the leader 2) no other node is draining which is indicated by the annotation.
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 see, thanks for clarifying
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.
@pliurh mind mentioning this in the commit message ? so its clear in the commit message how this mechanism is used to control node draining
pkg/daemon/daemon.go
Outdated
RetryPeriod: 1 * time.Second, | ||
Callbacks: leaderelection.LeaderCallbacks{ | ||
OnStartedLeading: func(ctx context.Context) { | ||
glog.V(2).Info("drainNode(): started leading") |
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 see in your log messages you've drainNode()
- should it not be getDrainLock()
?
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.
fixed
glog.V(2).Info("drainNode(): started leading") | ||
for { | ||
time.Sleep(1 * time.Second) | ||
if dn.drainable { |
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.
Outside of any concern for this PR because this pattern was here before this PR - but have you folks ever seen nodes getting stuck on this condition? It could happen if a node reboots and doesn't startup and daemonset is unable to update its draining status.
Then line 847 is blocked indefinitely.
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.
That is intentional. We don't want a configuration mistake to break more nodes. If users encounter such a problem, they'd better do some troubleshooting to find out why the node cannot come back.
55f619a
to
fb30f8c
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.
I would prefer the package updates be performed in a separate commit in the PR (easier to review this way). but would not block on it.
@SchSeba i see below you were requested as reviewer. once you approve this can be merged IMO
Utilize k8s leader election mechanism to prevent annotating nodes at the same time. The leader election mechanism requires the leader to keep updating the Lease object. But in our case, the node may reboot itself, then lose leadership. So I use a 2 layers lock here. The node can only start draining with 2 conditions: 1) it becomes the leader 2) no other node is draining which is indicated by the annotation.
Utilize k8s leader election mechanism to prevent annotating nodes
at the same time.