-
Notifications
You must be signed in to change notification settings - Fork 210
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 label-with-exclude-from-external-lbs
CLI argument to enable graceful removal/addition from external load balancers
#419
Conversation
I released the e2e checks that were waiting for approval. Thanks for re-submitting this! |
I will review asap. |
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.
Little detail: I think this should be opt-in.
What would you suggest calling the command line argument? |
I have no strong opinion :) |
I think it would be wise to clarify this (future) CLI flag's purpose in our documentation + include it (commented out) in our manifest. |
d57c317
to
fff8cdf
Compare
label-with-exclude-from-external-lbs
CLI argument to enable graceful removal/addition from external load balancers
I rebased with upstream/main, added a |
fff8cdf
to
a9cdeb4
Compare
I should have been clearer and mention no change in the helm chart, as the helm chart is trailing the release. Sorry for that. The manifest and docs are to be included in the release however. |
a9cdeb4
to
e5272c0
Compare
Ok, fixed. |
cmd/kured/main.go
Outdated
@@ -492,6 +552,9 @@ func rebootAsRequired(nodeID string, rebootCommand []string, sentinelCommand []s | |||
log.Fatal(err) | |||
} | |||
|
|||
// Remove ExcludeFromELBs label immediately to allow ELB registration | |||
disableExcludeFromELBs(client, nodeID) |
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 there a reason you only guard the enable, not the disable? I would expect no change to the labels by default if the option is disabled. (hence, adding a guard here too).
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 was thinking about the case of a user who disables the option during a reboot after the label has been added. In order to avoid leaving the rebooted node off of the external load balancers when the node is rebooted, disable() has to run on startup. On the other hand, there's no harm in running disable() when there's no label present since it won't do anything.
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 does an api call, so it doesn't do nothing ;)
However, it made me realise that an error in disableExcludeFromELBs (e.g. one that the API can throw) is not used in any way... Why do we return the error if it's to do nothing with it? How should we behave if the API call fails?
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.
Currently the returned error is being used in the unit tests.
In terms of what to do if the API call fails, I think it makes sense to make API failures in enableExcludeFromELBs()
fatal since success is a must for users who have enabled --label-with-exclude-from-external-lbs
.
On the other hand, I don't think API errors in disableExcludeFromELBs()
necessarily need to be fatal but it looks like similar operations such as annotation deletion failures are treated fatally elsewhere in the code.
Should we make the API failures fatal in enableExcludeFromELBs()
and disableExcludeFromELBs()
?
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.
What would you like to do here? Do you want to guard the disable and make API errors fatal?
Looks good overall, just a small final nit. |
Are there any changes that need to be made to the PR? |
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 I would like to discuss the guard and the last bit of the code.
cmd/kured/main.go
Outdated
@@ -492,6 +552,9 @@ func rebootAsRequired(nodeID string, rebootCommand []string, sentinelCommand []s | |||
log.Fatal(err) | |||
} | |||
|
|||
// Remove ExcludeFromELBs label immediately to allow ELB registration | |||
disableExcludeFromELBs(client, nodeID) |
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 does an api call, so it doesn't do nothing ;)
However, it made me realise that an error in disableExcludeFromELBs (e.g. one that the API can throw) is not used in any way... Why do we return the error if it's to do nothing with it? How should we behave if the API call fails?
I don't want to be a blocker for progress. If we feel it's a good feature, then let's move ahead... please let's just solve git conflicts and human ones ;) |
e5272c0
to
d49d805
Compare
Sounds good to me! I rebased with main, fixed the conflicts and am waiting for feedback on the changes you requested above. |
…ceful removal/addition from external load balancers Previously, kured issued the system reboot command without first removing nodes from any connected external load balancers (ELBs). This behavior caused downtime on restart because ELBs send traffic to kube-proxy pods running on nodes until the ELB health checks fail or the node is de-registered explicitly. This patch solves the problem by adding a command line argument (`label-with-exclude-from-external-lbs`) that, when enabled, adds a "node.kubernetes.io/exclude-from-external-load-balancers" label to nodes undergoing kured reboot. This label tells the Kubernetes control plane to de-register the affected node from any connected ELBs. The node label is removed after restart which causes the control plane to re-register the node with the ELBs. Close kubereboot#358
d49d805
to
14c898c
Compare
I fenced in |
@@ -493,6 +553,12 @@ func rebootAsRequired(nodeID string, rebootCommand []string, sentinelCommand []s | |||
log.Fatal(err) | |||
} | |||
|
|||
if labelWithELBX { |
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.
Don't we want to move this remove node label logic down into the the part where we know we're holding the lock? Similar to where we do if annotateNodes && !rebootRequired
and then delete node annotations?
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 disableExcludeFromELBs()
method can be run safely with or without the lock. Are there any particular cases you're thinking of where you would want the method to run only if the lock is present?
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 just thinking that if we do this when we're not holding the lock, that means we're doing it in every iteration. And that means that we're calling the apiserver for the node object every time. On a cluster with hundreds of thousands of nodes, with a small kured interval (e.g., 1 min), that means we're going to potentially be sending many apiserver requests every second.
If I understand correctly, the only reason we want to disable this label is to remove it after a successful reboot. In every scenario that fits that description, we should have the lock (because we only ever release the lock inside that block).
Does that make sense?
cc @dholbach @ckotzbauer for thoughts as well
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 agree with @jackfrancis, that we should avoid requesting the apiserver to excessive. The logic should be safe when only called with a lock being present.
This PR was automatically considered stale due to lack of activity. Please refresh it and/or join our slack channels to highlight it, before it automatically closes (in 7 days). |
This PR was automatically considered stale due to lack of activity. Please refresh it and/or join our slack channels to highlight it, before it automatically closes (in 7 days). |
/remove no-pr-activity |
This PR was automatically considered stale due to lack of activity. Please refresh it and/or join our slack channels to highlight it, before it automatically closes (in 7 days). |
Previously, kured issued the system reboot command without first removing nodes from any connected external load balancers (ELBs).
This behavior caused downtime on restart because ELBs send traffic to kube-proxy pods running on nodes until the ELB health checks fail or the node is de-registered explicitly.
This patch solves the problem by adding a command line argument (
label-with-exclude-from-external-lbs
) that, when enabled, adds a "node.kubernetes.io/exclude-from-external-load-balancers" label to nodes undergoing kured reboot. This label tells the Kubernetes control plane to de-register the affected node from any connected ELBs. The node label is removed after restart which causes the control plane to re-register the node with the ELBs.Close #358