Skip to content

Commit f96ed67

Browse files
authored
Merge pull request #7676 from macsko/allow_to_prefix_provisioning_class_name_to_filter_prs
Allow to prefix provisioningClassName to filter provisioning requests
2 parents 02e3d19 + 90eabc6 commit f96ed67

File tree

14 files changed

+395
-77
lines changed

14 files changed

+395
-77
lines changed

cluster-autoscaler/FAQ.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,19 @@ When using this class, Cluster Autoscaler performs following actions:
629629
Adds a Provisioned=True condition to the ProvReq if capacity is available.
630630
Adds a BookingExpired=True condition when the 10-minute reservation period expires.
631631

632+
Since Cluster Autoscaler version 1.33, it is possible to configure the autoscaler
633+
to process only subset of check capacity ProvisioningRequests and ignore the rest.
634+
It should be done with caution by specifying `--check-capacity-processor-instance=<name>` flag.
635+
Then, ProvReq Parameters map should contain a key "processorInstance" with a value equal to the configured instance name.
636+
637+
This allows to run two Cluster Autoscalers in the cluster, but the second instance (likely this with configured instance name)
638+
**should only** handle check capacity ProvisioningRequests and not overlap node groups with the main instance.
639+
It is responsibility of the user to ensure the capacity checks are not overlapping.
640+
Best-effort atomic ProvisioningRequests processing is disabled in the instance that has this flag set.
641+
642+
For backwards compatibility, it is possible to differentiate the ProvReqs by prefixing provisioningClassName with the instance name,
643+
but it is **not recommended** and will be removed in CA 1.35.
644+
632645
* `best-effort-atomic-scale-up.autoscaling.x-k8s.io` (supported from Cluster Autoscaler version 1.30.2 or later).
633646
When using this class, Cluster Autoscaler performs following actions:
634647

@@ -735,12 +748,12 @@ setting the following flag in your Cluster Autoscaler configuration:
735748
3. **Batch Size**: Set the maximum number of CheckCapacity ProvisioningRequests
736749
to process in a single iteration by setting the following flag in your Cluster
737750
Autoscaler configuration:
738-
`--max-batch-size=<batch-size>`. The default value is 10.
751+
`--check-capacity-provisioning-request-max-batch-size=<batch-size>`. The default value is 10.
739752

740753
4. **Batch Timebox**: Set the maximum time in seconds that Cluster Autoscaler will
741754
spend processing CheckCapacity ProvisioningRequests in a single iteration by
742755
setting the following flag in your Cluster Autoscaler configuration:
743-
`--batch-timebox=<timebox>`. The default value is 10s.
756+
`--check-capacity-provisioning-request-batch-timebox=<timebox>`. The default value is 10s.
744757

745758
****************
746759

@@ -973,13 +986,15 @@ The following startup parameters are supported for cluster autoscaler:
973986
| `bulk-mig-instances-listing-enabled` | Fetch GCE mig instances in bulk instead of per mig | |
974987
| `bypassed-scheduler-names` | Names of schedulers to bypass. If set to non-empty value, CA will not wait for pods to reach a certain age before triggering a scale-up. | |
975988
| `check-capacity-batch-processing` | Whether to enable batch processing for check capacity requests. | |
989+
| `check-capacity-processor-instance` | Name of the processor instance. Only ProvisioningRequests that define this name in their parameters with the key "processorInstance" will be processed by this CA instance. It only refers to check capacity ProvisioningRequests, but if not empty, best-effort atomic ProvisioningRequests processing is disabled in this instance. Not recommended: Until CA 1.35, ProvisioningRequests with this name as prefix in their class will be also processed. | |
976990
| `check-capacity-provisioning-request-batch-timebox` | Maximum time to process a batch of provisioning requests. | 10s |
977991
| `check-capacity-provisioning-request-max-batch-size` | Maximum number of provisioning requests to process in a single batch. | 10 |
978992
| `cloud-config` | The path to the cloud provider configuration file. Empty string for no configuration file. | |
979993
| `cloud-provider` | Cloud provider type. Available values: [aws,azure,gce,alicloud,cherryservers,cloudstack,baiducloud,magnum,digitalocean,exoscale,externalgrpc,huaweicloud,hetzner,oci,ovhcloud,clusterapi,ionoscloud,kamatera,kwok,linode,bizflycloud,brightbox,equinixmetal,vultr,tencentcloud,civo,scaleway,rancher,volcengine] | "gce" |
980994
| `cloud-provider-gce-l7lb-src-cidrs` | CIDRs opened in GCE firewall for L7 LB traffic proxy & health checks | 130.211.0.0/22,35.191.0.0/16 |
981995
| `cloud-provider-gce-lb-src-cidrs` | CIDRs opened in GCE firewall for L4 LB traffic proxy & health checks | 130.211.0.0/22,209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 |
982996
| `cluster-name` | Autoscaled cluster name, if available | |
997+
| `cluster-snapshot-parallelism` | Maximum parallelism of cluster snapshot creation. | 16 |
983998
| `clusterapi-cloud-config-authoritative` | Treat the cloud-config flag authoritatively (do not fallback to using kubeconfig flag). ClusterAPI only | |
984999
| `cordon-node-before-terminating` | Should CA cordon nodes before terminating during downscale process | |
9851000
| `cores-total` | Minimum and maximum number of cores in cluster, in the format <min>:<max>. Cluster autoscaler will not scale the cluster beyond these numbers. | "0:320000" |
@@ -1015,7 +1030,13 @@ The following startup parameters are supported for cluster autoscaler:
10151030
| `kube-client-qps` | QPS value for kubernetes client. | 5 |
10161031
| `kubeconfig` | Path to kubeconfig file with authorization and master location information. | |
10171032
| `kubernetes` | Kubernetes master location. Leave blank for default | |
1018-
| `lease-resource-name` | The lease resource to use in leader election. | "cluster-autoscaler" |
1033+
| `leader-elect` | Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability. | true |
1034+
| `leader-elect-lease-duration` | The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled. | 15s |
1035+
| `leader-elect-renew-deadline` | The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than the lease duration. This is only applicable if leader election is enabled. | 10s |
1036+
| `leader-elect-resource-lock` | The type of resource object that is used for locking during leader election. Supported options are 'leases'. | "leases" |
1037+
| `leader-elect-resource-name` | The name of resource object that is used for locking during leader election. | "cluster-autoscaler" |
1038+
| `leader-elect-resource-namespace` | The namespace of resource object that is used for locking during leader election. | |
1039+
| `leader-elect-retry-period` | The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled. | 2s |
10191040
| `log-backtrace-at` | when logging hits line file:N, emit a stack trace | :0 |
10201041
| `log-dir` | If non-empty, write log files in this directory (no effect when -logtostderr=true) | |
10211042
| `log-file` | If non-empty, use this log file (no effect when -logtostderr=true) | |

cluster-autoscaler/config/autoscaling_options.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ type AutoscalingOptions struct {
313313
DynamicResourceAllocationEnabled bool
314314
// ClusterSnapshotParallelism is the maximum parallelism of cluster snapshot creation.
315315
ClusterSnapshotParallelism int
316+
// CheckCapacityProcessorInstance is the name of the processor instance.
317+
// Only ProvisioningRequests that define this name in their parameters with the key "processorInstance" will be processed by this CA instance.
318+
// It only refers to check capacity ProvisioningRequests, but if not empty, best-effort atomic ProvisioningRequests processing is disabled in this instance.
319+
// Not recommended: Until CA 1.35, ProvisioningRequests with this name as prefix in their class will be also processed.
320+
CheckCapacityProcessorInstance string
316321
}
317322

318323
// KubeClientOptions specify options for kube client

cluster-autoscaler/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ var (
283283
forceDeleteLongUnregisteredNodes = flag.Bool("force-delete-unregistered-nodes", false, "Whether to enable force deletion of long unregistered nodes, regardless of the min size of the node group the belong to.")
284284
enableDynamicResourceAllocation = flag.Bool("enable-dynamic-resource-allocation", false, "Whether logic for handling DRA (Dynamic Resource Allocation) objects is enabled.")
285285
clusterSnapshotParallelism = flag.Int("cluster-snapshot-parallelism", 16, "Maximum parallelism of cluster snapshot creation.")
286+
checkCapacityProcessorInstance = flag.String("check-capacity-processor-instance", "", "Name of the processor instance. Only ProvisioningRequests that define this name in their parameters with the key \"processorInstance\" will be processed by this CA instance. It only refers to check capacity ProvisioningRequests, but if not empty, best-effort atomic ProvisioningRequests processing is disabled in this instance. Not recommended: Until CA 1.35, ProvisioningRequests with this name as prefix in their class will be also processed.")
286287
)
287288

288289
func isFlagPassed(name string) bool {
@@ -464,6 +465,7 @@ func createAutoscalingOptions() config.AutoscalingOptions {
464465
ForceDeleteLongUnregisteredNodes: *forceDeleteLongUnregisteredNodes,
465466
DynamicResourceAllocationEnabled: *enableDynamicResourceAllocation,
466467
ClusterSnapshotParallelism: *clusterSnapshotParallelism,
468+
CheckCapacityProcessorInstance: *checkCapacityProcessorInstance,
467469
}
468470
}
469471

@@ -539,7 +541,7 @@ func buildAutoscaler(context ctx.Context, debuggingSnapshotter debuggingsnapshot
539541
return nil, nil, err
540542
}
541543

542-
ProvisioningRequestInjector, err = provreq.NewProvisioningRequestPodsInjector(restConfig, opts.ProvisioningRequestInitialBackoffTime, opts.ProvisioningRequestMaxBackoffTime, opts.ProvisioningRequestMaxBackoffCacheSize, opts.CheckCapacityBatchProcessing)
544+
ProvisioningRequestInjector, err = provreq.NewProvisioningRequestPodsInjector(restConfig, opts.ProvisioningRequestInitialBackoffTime, opts.ProvisioningRequestMaxBackoffTime, opts.ProvisioningRequestMaxBackoffCacheSize, opts.CheckCapacityBatchProcessing, opts.CheckCapacityProcessorInstance)
543545
if err != nil {
544546
return nil, nil, err
545547
}
@@ -558,7 +560,7 @@ func buildAutoscaler(context ctx.Context, debuggingSnapshotter debuggingsnapshot
558560

559561
scaleUpOrchestrator := provreqorchestrator.NewWrapperOrchestrator(provreqOrchestrator)
560562
opts.ScaleUpOrchestrator = scaleUpOrchestrator
561-
provreqProcesor := provreq.NewProvReqProcessor(client)
563+
provreqProcesor := provreq.NewProvReqProcessor(client, opts.CheckCapacityProcessorInstance)
562564
opts.LoopStartNotifier = loopstart.NewObserversList([]loopstart.Observer{provreqProcesor})
563565

564566
podListProcessor.AddProcessor(provreqProcesor)

cluster-autoscaler/processors/provreq/injector.go

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type ProvisioningRequestPodsInjector struct {
4444
client *provreqclient.ProvisioningRequestClient
4545
lastProvisioningRequestProcessTime time.Time
4646
checkCapacityBatchProcessing bool
47+
checkCapacityProcessorInstance string
4748
}
4849

4950
// IsAvailableForProvisioning checks if the provisioning request is the correct state for processing and provisioning has not been attempted recently.
@@ -93,16 +94,28 @@ func (p *ProvisioningRequestPodsInjector) MarkAsFailed(pr *provreqwrapper.Provis
9394
p.UpdateLastProcessTime()
9495
}
9596

97+
func (p *ProvisioningRequestPodsInjector) isSupportedClass(pr *provreqwrapper.ProvisioningRequest) bool {
98+
return provisioningrequest.SupportedProvisioningClass(pr.ProvisioningRequest, p.checkCapacityProcessorInstance)
99+
}
100+
101+
func (p *ProvisioningRequestPodsInjector) isSupportedCheckCapacityClass(pr *provreqwrapper.ProvisioningRequest) bool {
102+
return provisioningrequest.SupportedCheckCapacityClass(pr.ProvisioningRequest, p.checkCapacityProcessorInstance)
103+
}
104+
105+
func (p *ProvisioningRequestPodsInjector) shouldMarkAsAccepted(pr *provreqwrapper.ProvisioningRequest) bool {
106+
// Don't mark as accepted the check capacity ProvReq when batch processing is enabled.
107+
// It will be marked later, in parallel, during processing the requests.
108+
return !p.checkCapacityBatchProcessing || !p.isSupportedCheckCapacityClass(pr)
109+
}
110+
96111
// GetPodsFromNextRequest picks one ProvisioningRequest meeting the condition passed using isSupportedClass function, marks it as accepted and returns pods from it.
97-
func (p *ProvisioningRequestPodsInjector) GetPodsFromNextRequest(
98-
isSupportedClass func(*provreqwrapper.ProvisioningRequest) bool,
99-
) ([]*apiv1.Pod, error) {
112+
func (p *ProvisioningRequestPodsInjector) GetPodsFromNextRequest() ([]*apiv1.Pod, error) {
100113
provReqs, err := p.client.ProvisioningRequests()
101114
if err != nil {
102115
return nil, err
103116
}
104117
for _, pr := range provReqs {
105-
if !isSupportedClass(pr) {
118+
if !p.isSupportedClass(pr) {
106119
continue
107120
}
108121

@@ -117,16 +130,13 @@ func (p *ProvisioningRequestPodsInjector) GetPodsFromNextRequest(
117130
p.MarkAsFailed(pr, provreqconditions.FailedToCreatePodsReason, err.Error())
118131
continue
119132
}
120-
// Don't mark as accepted the check capacity ProvReq when batch processing is enabled.
121-
// It will be marked later, in parallel, during processing the requests.
122-
if pr.Spec.ProvisioningClassName == v1.ProvisioningClassCheckCapacity && p.checkCapacityBatchProcessing {
123-
p.UpdateLastProcessTime()
133+
if p.shouldMarkAsAccepted(pr) {
134+
if err := p.MarkAsAccepted(pr); err != nil {
135+
continue
136+
}
124137
return podsFromProvReq, nil
125138
}
126-
if err := p.MarkAsAccepted(pr); err != nil {
127-
continue
128-
}
129-
139+
p.UpdateLastProcessTime()
130140
return podsFromProvReq, nil
131141
}
132142
return nil, nil
@@ -152,7 +162,7 @@ func (p *ProvisioningRequestPodsInjector) GetCheckCapacityBatch(maxPrs int) ([]P
152162
if len(prsWithPods) >= maxPrs {
153163
break
154164
}
155-
if pr.Spec.ProvisioningClassName != v1.ProvisioningClassCheckCapacity {
165+
if !p.isSupportedCheckCapacityClass(pr) {
156166
continue
157167
}
158168
if !p.IsAvailableForProvisioning(pr) {
@@ -175,15 +185,7 @@ func (p *ProvisioningRequestPodsInjector) Process(
175185
_ *context.AutoscalingContext,
176186
unschedulablePods []*apiv1.Pod,
177187
) ([]*apiv1.Pod, error) {
178-
podsFromProvReq, err := p.GetPodsFromNextRequest(
179-
func(pr *provreqwrapper.ProvisioningRequest) bool {
180-
_, found := provisioningrequest.SupportedProvisioningClasses[pr.Spec.ProvisioningClassName]
181-
if !found {
182-
klog.Warningf("Provisioning Class %s is not supported for ProvReq %s/%s", pr.Spec.ProvisioningClassName, pr.Namespace, pr.Name)
183-
}
184-
return found
185-
})
186-
188+
podsFromProvReq, err := p.GetPodsFromNextRequest()
187189
if err != nil {
188190
return unschedulablePods, err
189191
}
@@ -195,7 +197,7 @@ func (p *ProvisioningRequestPodsInjector) Process(
195197
func (p *ProvisioningRequestPodsInjector) CleanUp() {}
196198

197199
// NewProvisioningRequestPodsInjector creates a ProvisioningRequest filter processor.
198-
func NewProvisioningRequestPodsInjector(kubeConfig *rest.Config, initialBackoffTime, maxBackoffTime time.Duration, maxCacheSize int, checkCapacityBatchProcessing bool) (*ProvisioningRequestPodsInjector, error) {
200+
func NewProvisioningRequestPodsInjector(kubeConfig *rest.Config, initialBackoffTime, maxBackoffTime time.Duration, maxCacheSize int, checkCapacityBatchProcessing bool, checkCapacityProcessorInstance string) (*ProvisioningRequestPodsInjector, error) {
199201
client, err := provreqclient.NewProvisioningRequestClient(kubeConfig)
200202
if err != nil {
201203
return nil, err
@@ -208,6 +210,7 @@ func NewProvisioningRequestPodsInjector(kubeConfig *rest.Config, initialBackoffT
208210
clock: clock.RealClock{},
209211
lastProvisioningRequestProcessTime: time.Now(),
210212
checkCapacityBatchProcessing: checkCapacityBatchProcessing,
213+
checkCapacityProcessorInstance: checkCapacityProcessorInstance,
211214
}, nil
212215
}
213216

0 commit comments

Comments
 (0)