Repository navigation
feat(source): skip nodes being removed or excluded from load balancers - #6860
Conversation
|
Welcome @mindw! |
|
Hi @mindw. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Tip We noticed you've done this a few times! Consider joining the org to skip this step and gain Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
Not required,. Same functionality supported with --target-template=TARGET-TEMPLATE and or --fqdn-target-template=FQDN-TARGET-TEMPLATE
This shouldn't be read as a signal. PRs maintainers don't find valuable are typically left to expire and get auto-closed by the bot. |
|
/hold |
|
I unhold for now. As need too review it, maybe not supported feature /hold cancel |
|
#6844 aleternative to my understanding |
|
I agree with @ivankatliarchuk. Keeping short-lived nodes out is a cluster-wide concern, so an annotation on every Service feels like the wrong place for it.
Could we extend |
|
On the earlier PRs: fair point. I've dropped that line from the description. Templates. On the The closest setup I can see is the #6844. As I read proposal 007,
A selector keeps short-lived Nodes out of the record for their whole life. It also covers cases with no taint to key on: the Cluster Autoscaler, or pinning a NodePort to an edge pool. On where it belongs: which Nodes should back a NodePort record can differ per Service, for example ingress on an edge pool and another Service elsewhere. That's why it's an annotation. |
|
Agreed, templates and Still, node lifecycle is a cluster-wide concern, not a per-Service one. Could you instead:
A disrupted node then leaves the record within seconds, while it's still draining. |
|
Agreed, it belongs at cluster level, so I'll drop the annotation. What you describe is close to how the cloud-provider service controller picks Nodes for LoadBalancer Services (
That label is the cluster-wide way to keep a Node out of load balancing.
A NodePort record is that kind of load balancer, done in DNS. So I'd rework this PR to:
The taints only cover the end of a Node's life. Resolvers keep a removed IP until the TTL expires, which is 300s by default on AWS. So when an empty Node is consolidated, or a Spot Node is interrupted, clients can still be sent to it for that long. (2) handles Nodes that are short-lived by design: with Karpenter, setting the label in the NodePool template keeps its Nodes out of the record for their whole life. Two questions:
|
|
b0a8622 to
ee9145e
Compare
|
@mloiseleur reworked as agreed. The annotation is gone, and I've updated the title and description.
One behaviour change to look at: with |
|
/ok-to-test |
Coverage Report for CI Build 43442799060Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage increased (+0.04%) to 83.512%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions10 previously-covered lines in 2 files lost coverage.
Coverage Stats
💛 - Coveralls |
881779c to
653bf0a
Compare
mloiseleur
left a comment
There was a problem hiding this comment.
Thanks, this is the shape we asked for.
Filtering before the Local tier ranking is a nice fix, and the Node update filter looks right (the transform already strips conditions, and the service source does not read Node annotations).
Only wording nits left.
--exclude-unschedulable now also skips Nodes that are being removed, in the node and service sources: Nodes with deletionTimestamp set, and Nodes tainted ToBeDeletedByClusterAutoscaler or karpenter.sh/disrupted. NodePort targets skip Nodes labelled node.kubernetes.io/exclude-from-external-load-balancers, with the same rule as the cloud-provider service controller: any value that doesn't parse as false excludes the Node. The node source doesn't use the label. - externalTrafficPolicy=Local drops excluded Nodes, cordoned ones included, before the readiness tiers are compared, so the best tier among the remaining Nodes wins instead of the records ending up empty. - The service source re-syncs on Node events when it has a Node informer. Updates that leave addresses, labels, taints, spec.unschedulable and the deletion state unchanged are ignored. Docs: Service source NodePort section, node source and the --exclude-unschedulable help text.
653bf0a to
da5a5ed
Compare
mloiseleur
left a comment
There was a problem hiding this comment.
Thanks, all suggestions applied.
Co-authored-by: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com>
|
/lgtm |
|
/approve |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ivankatliarchuk The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What does it do ?
--exclude-unschedulablealso skips Nodes that are being removed, in thenodeandservicesources. As well as cordoned Nodes, it now skips Nodes that:deletionTimestampset;ToBeDeletedByClusterAutoscaler(Cluster Autoscaler) orkarpenter.sh/disrupted(Karpenter). Both add the taint before they drain and delete the Node.The flag defaults to
true, so this is on by default.--no-exclude-unschedulableturns it off.NodePort targets skip Nodes labelled
node.kubernetes.io/exclude-from-external-load-balancers, with the same rule as the cloud-provider service controller (nodeIncludedPredicate): any value that doesn't parse as false excludes the Node. There is no flag for this. Thenodesource doesn't use the label.With
externalTrafficPolicy: Local, both checks now run before the pod readiness tiers are compared. If the best pods run on excluded Nodes, the records use the best tier on the remaining Nodes instead of ending up empty. Before this, cordoned Nodes were dropped after the tiers were compared.The service source re-syncs on Node events whenever it has a Node informer (NodePort enabled in
--service-type-filter). Adding or deleting a Node triggers a sync. An update triggers one only if it changes the addresses, labels, taints,spec.unschedulableor deletion state, so status reports don't.On upgrade, Nodes being removed leave
nodeand NodePort records, and Nodes that already carry the label leave NodePort records.Docs: the NodePort part of
docs/sources/service.md,docs/sources/nodes.md, and the--exclude-unschedulablehelp text indocs/flags.md.Motivation
NodePort records list every Node. With an autoscaler many Nodes are short-lived, so clients resolve to Nodes that were just removed.
deletionTimestampare the signals that kube-proxy (NodeEligible, KEP-3836) and the cloud-provider service controller (stableNodeSetPredicates) use. kube-proxy doesn't check Karpenter's taint, which Karpenter adds before it deletes the Node.k8s.io/apidefines it as: "the node should not be considered as a target for external load-balancers which use nodes as a second hop".--interval.Following the review discussion, this replaces the
nodeport-filterannotation that the PR first proposed. #916 and #4693 asked for a way to keep Nodes out of NodePort records too.More