Skip to content

Unexpected behaviour using kubectl scale with a topology managed cluster #7395

Open

Description

@killianmuldoon

When using kubectl scale machinedeployment or kubectl scale kcp with a topology managed cluster the command succeeds but does not have the expected result. Depending on how quickly the topology controller reacts to the change the resource either doesn't appear to scale at all or else it scales up and then scales down quickly (in line with replicas specified in the cluster topology).

There's two options to deal with this IMO:

  1. Intercept the scale request and send it to the Cluster Topology instead.
  2. Block a scale request when the scalable resource is topology managed and replicas is set.

Blocking the request is the most feasible IMO as intercepting the request would be control plane specific i.e. we could implement it on KCP but it would have to be done in all other control plane providers. It would also mean adding a client to all scalable resources, and it subverts some expectations about how the API should work. When blocking we can return a useful error message explaining how to make a resource independently scalable i.e. unsetting replicas.

I haven't done a POC, but I think it would be feasible to both block changing the replicas field and block access to the scale subresource. This would have an impact on autoscaling, with the autoscaler returning a useful error when trying to improperly change a managed cluster's scalable resource rather than having the scale operation be apparently successful, but resulting in no spec change.

This is also, presumably, an issue when a MachineSet is managed by a MachineDeployment, but scaling an MS individually is probably a less established pattern.

/area topology
/cc @jackfrancis @sbueringer

Activity

  1. fabriziopandini commented on Oct 12, 2022

    @fabriziopandini
    Member

    /triage accepted

    Ideally, the cluster should become the scalable resource in this case, but I'm not sure we can achieve this given that there could be many scalable things in one cluster.

    +1 to explore ideas about how to make this possible/less surprising for the users

  2. added
    triage/acceptedIndicates an issue or PR is ready to be actively worked on.
    and removed
    needs-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.
    on Oct 12, 2022
  3. killianmuldoon commented on Oct 12, 2022

    @killianmuldoon
    ContributorAuthor

    Ideally, the cluster should become the scalable resource in this case, but I'm not sure we can achieve this given that there could be many scalable things in one cluster

    Agreed - especially with multiple MachineDeployments this could become really unergonomic - i.e. kubectl scale cluster md $MD_NAME --replicas=3

  4. sbueringer commented on Oct 12, 2022

    @sbueringer
    Member

    Looking at how scale is implemented on the Kubernets side this means we need spec/status fields for replicas in the Cluster and I think we can't have multiple of them:

    scale:
    labelSelectorPath: .status.selector
    specReplicasPath: .spec.replicas
    statusReplicasPath: .status.replicas
    status: {}

    So I think making this happen somehow requires a very creative solution.

    Intercept the scale request and send it to the Cluster Topology instead.

    I can't imagine a good solution for this

    This would have an impact on autoscaling, with the autoscaler returning a useful error when trying to improperly change a managed cluster's scalable resource rather than having the scale operation be apparently successful, but resulting in no spec change.

    We would have to make sure we block this request only if the topology controller actually cares about the replicas field. Otherwise we break the autoscaler.

    Additionally, I have no idea if the autoscaler is using update/patch or the scale subresource.

  5. sbueringer commented on Oct 12, 2022

    @sbueringer
    Member

    Agreed - especially with multiple MachineDeployments this could become really unergonomic - i.e. kubectl scale cluster md $MD_NAME --replicas=3

    This CLI syntax 100% requires a KEP for kubectl as it's not supported today.

  6. killianmuldoon commented on Oct 12, 2022

    @killianmuldoon
    ContributorAuthor

    Additionally, I have no idea if the autoscaler is using update/patch or the scale subresource.

    I think if we implement either of the solutions it would have to work for both the scale subresource and for updating the replicas field.

    This CLI syntax 100% requires a KEP for kubectl as it's not supported today.

    I'm definitely not up for proposing it 😆 - just expressing the level of granularity this would need because of the multiple types of scalable resource and the multiple actual resource in the Cluster Topology.

  7. sbueringer commented on Oct 12, 2022

    @sbueringer
    Member

    Just wanted to make clear that we're talking about changing a feature / trying to workaround a feature which is almost entirely implemented upstream (kubectl / kube-apiserver) :)

  8. killianmuldoon commented on Oct 12, 2022

    @killianmuldoon
    ContributorAuthor

    Just had a look - it looks like the Cluster Autoscaler uses https://pkg.go.dev/k8s.io/client-go/scale which works on the scale subresource. But we can't be sure this is the case for other autoscaler implementations of course.

  9. jackfrancis commented on Oct 14, 2022

    @jackfrancis
    Contributor

    Thanks for facilitating this discussion @killianmuldoon

    @elmiko a brief tour through the capi provider of cluster-autoscaler suggests that it doesn't work with ClusterClass at all

    Maybe this option will solve for a lot of the issues we're observing:

    Intercept the scale request and send it to the Cluster Topology instead.

    But it would probably be better to have autoscaler be ClusterClass-aware, and initiate scale events against the appropriate Cluster sub-resource instead of the MachineDeployments (and when MachinePools support lands for autoscaler, same idea).

    Does that sound right?

  10. fabriziopandini commented on Oct 14, 2022

    @fabriziopandini
    Member

    I was thinking at this and looking at options to make it work for the 80% of the use cases

    Is it acceptable to say that kubectl scale should scale the first MachineDeployment?

    Why this approach?
    I assume scaling the control plane is not a frequent operator, so I don't see value in providing a shortcut on this operation (it could also be seen as a sort of protection to the control plane)

    So, with the CP out of the table, kubectl scale should target MachineDeployments, and assuming having only 1 MD is the most common use case, it should target the first

    Does this makes sense?

  11. fabriziopandini commented on Oct 14, 2022

    @fabriziopandini
    Member

    Wrt to the auto scaler, AFAIK we are not setting replicas in the cluster topology, so everything should work as usual

  12. killianmuldoon commented on Oct 17, 2022

    @killianmuldoon
    ContributorAuthor

    The first MachineDeployment is probably the 80 percent case but IMO it's not a great solution to this problem. It's not extensible to cover any other use case which makes it confusing and frustrating for users. It introduces inconsistency into the management of Clusters, and in the API which could cause further complications down the line.

    I think blocking the request is probably a better solution, even if it means losing kubectl scale.

  13. 1 remaining item

  14. jackfrancis commented on Oct 17, 2022

    @jackfrancis
    Contributor

    +1 on not doing the "just choose the first MachineDeployment" approach, as that seems too non-deterministic

  15. elmiko commented on Oct 17, 2022

    @elmiko
    Contributor

    from @jackfrancis

    @elmiko a brief tour through the capi provider of cluster-autoscaler suggests that it doesn't work with ClusterClass at all

    correct, autoscaler does not know about ClusterClass

    Maybe this option will solve for a lot of the issues we're observing:

    Intercept the scale request and send it to the Cluster Topology instead.

    But it would probably be better to have autoscaler be ClusterClass-aware, and initiate scale events against the appropriate Cluster sub-resource instead of the MachineDeployments (and when MachinePools support lands for autoscaler, same idea).

    Does that sound right?

    i have to admit that i don't know all the details of the relationship between ClusterClass and MachineDeployment, but certainly we could have the autoscaler become aware of ClusterClasses and then add that into the workflow that it follows. it sounds like there might be a case where the autoscaler would detect that a ClusterClass is owning (not sure if that is correct term) /some/ scalable resource (Machine[Deployment|Set|Pool]) and when the autoscaler wants to scale that resource then we would make a decision to choose which scalable resource gets updated. do i have that correct?

    from @fabriziopandini

    Wrt to the auto scaler, AFAIK we are not setting replicas in the cluster topology, so everything should work as usual

    given that, we might not need to do anything unless we want to build this out in the autoscaler.

    fwiw, i think we should keep the autoscaler as simple as possible with respect to the scalable CAPI resources.

  16. jackfrancis commented on Oct 17, 2022

    @jackfrancis
    Contributor

    I just want to be clear for any other folks reading this thread now and in the future: the cluster-api cluster-autoscaler not only doesn't know about ClusterClass, but it will 100% not work. So for folks running ClusterClass-enabled Cluster API clusters, you can not use cluster-autoscaler at this time.

    Someone correct me if I'm wrong!

  17. sbueringer commented on Oct 18, 2022

    @sbueringer
    Member

    I just want to be clear for any other folks reading this thread now and in the future: the cluster-api cluster-autoscaler not only doesn't know about ClusterClass, but it will 100% not work. So for folks running ClusterClass-enabled Cluster API clusters, you can not use cluster-autoscaler at this time.

    I think this is not correct. If you want to use autoscaler, you just don't set a replica field in Cluster.spec.topology.workers..... The topology controller will create the MD without specifying replicas. Defaulting will set replicas to 1. From then on the cluster-autscaler can modify the replicas in MD and the topology controller doesn't care and doesn't enforce any value on the MD spec field.

    We have a limitation regarding ClusterClass and auto scaler, but that is that today we can't set top-level annotations on MDs via Cluster.spec.topology to "fine-tune" the autoscaler. (@elmiko correct me if I'm wrong and the min/max annotations (I don't remember which) are mandatory, if they are, then autoscaler really doesn't work right now with ClusterClass until we implemented the annotation propagation)

  18. enxebre commented on Oct 18, 2022

    @enxebre
    Member

    Hey folks, great dicussion, can you help understand and try to scope down what's the concrete issue / use case here?

    Unexpected behaviour using kubectl scale with a topology managed cluster
    When using kubectl scale machinedeployment or kubectl scale kcp with a topology managed cluster the command succeeds but does not have the expected result. Depending on how quickly the topology controller reacts to the change the resource either doesn't appear to scale at all or else it scales up and then scales down quickly (in line with replicas specified in the cluster topology).

    To me, the above describes expected and reasonable behaviour. If you express intent for a resource that is managed by another entity (clusterClass in this case), they will fight. That's kube by design, entities being clusterClass, kubectl, autoscaler or anything else is circumstantial here.
    This is basically a tradeoff of using clusterClass that should be documented, as a user you have deliberately chosen to use an authority for managing the underlying resources. Now, if we consider this insufficient/poor UX I think we should focus on making our semantics/primitives more meaningful and flexible, I don't think we should be implementing non standard kubectl logic or non standard API behaviour (I'd find that to be truly unexpected behaviour).

    But then, based on @sbueringer comment it seems it is already the case that we support this more flexible use case and that the undesired UX @killianmuldoon describes that originated this issue has already a very reasonable alternative, i.e.

    you just don't set a replica field in Cluster.spec.topology.workers..... The topology controller will create the MD without specifying replicas. Defaulting will set replicas to 1

    So all seems fairly reasonable to me as it is (pending fixing the limitation on annotations Stefan mentioned).
    Now, there's some discussion around wanting a UX to use the Cluster as a scalable resource that signal to the underlying scalable resources:
    Can we describe use cases for this? In my mind, you'll usually want to scale a particular scalable resource which would allocate a particular group of workloads (This is true for autoscaler as well, it knows about homogenous nodeGoups). This is possible today already by using scale sub resources over exiting scalable resources MD/MS/MP (you just don't set a replica field in Cluster.spec.topology.workers) or expressing intent in clusterClass as the source of truth. Thinking of cluster as a first class scalable resource feels artificial to me.

  19. elmiko commented on Oct 20, 2022

    @elmiko
    Contributor

    We have a limitation regarding ClusterClass and auto scaler, but that is that today we can't set top-level annotations on MDs via Cluster.spec.topology to "fine-tune" the autoscaler. (@elmiko correct me if I'm wrong and the min/max annotations (I don't remember which) are mandatory, if they are, then autoscaler really doesn't work right now with ClusterClass until we implemented the annotation propagation)

    correct, they are required and must be on only the MD or MS.

  20. k8s-triage-robot commented on Jan 18, 2023

    @k8s-triage-robot

    The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs.

    This bot triages issues and PRs according to the following rules:

    • After 90d of inactivity, lifecycle/stale is applied
    • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
    • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

    You can:

    • Mark this issue or PR as fresh with /remove-lifecycle stale
    • Mark this issue or PR as rotten with /lifecycle rotten
    • Close this issue or PR with /close
    • Offer to help out with Issue Triage

    Please send feedback to sig-contributor-experience at kubernetes/community.

    /lifecycle stale

  21. added
    lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale.
    on Jan 18, 2023
  22. fabriziopandini commented on Apr 11, 2024

    @fabriziopandini
    Member

    /kind feature
    /priority backlog

  23. added
    kind/featureCategorizes issue or PR as related to a new feature.
    priority/backlogHigher priority than priority/awaiting-more-evidence.
    on Apr 11, 2024
  24. sbueringer commented on Apr 12, 2024

    @sbueringer
    Member

    My tl;dr (correct me if I'm wrong)

    A proper way to address this would be the following

    We would have to make sure we block this request only if the topology controller actually cares about the replicas field.

    So this means a webhook on the scale subresource of KCP & MD which blocks the scale request when:
    a) KCP & MD belong to a ClusterClass based cluster
    b) the corresponding replica field is set in Custer.spec.topology

  25. added
    help wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.
    on May 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/clusterclassIssues or PRs related to clusterclasshelp wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.kind/featureCategorizes issue or PR as related to a new feature.lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale.priority/backlogHigher priority than priority/awaiting-more-evidence.triage/acceptedIndicates an issue or PR is ready to be actively worked on.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions