Skip to content

Commit 70fc12e

Browse files
committed
Refactor cloud provider builder into a dynamic registration pattern
This comprehensive refactoring transitions the Cluster Autoscaler's cloud provider initialization from a hardcoded, monolithic switch statement to a decoupled, dynamic registration pattern. Motivation: Previously, the core cloud provider builder maintained direct dependencies on every supported cloud provider implementation. This architectural coupling forced the Cluster Autoscaler to pull in a massive number of transitive dependencies for all providers (AWS, Azure, GCE, etc.) regardless of which one was actually used. This resulted in significant "dependency bloat," unnecessarily large binary sizes, and long build times. It was particularly burdensome for external forks or specialized deployments that only required a single provider. Key Architectural Improvements: 1. Centralized Registration: The cloud provider initialization logic is now centralized in the `cloudprovider/builder` package. Each cloud provider implementation is responsible for registering its own builder function via an `init()` block. 2. True Decoupling: The core builder no longer has any direct knowledge or compile-time dependencies on specific provider implementations. It interacts solely with a registry of builder functions. 3. Dynamic Provider Discovery: `AvailableCloudProviders()` is now a dynamic function that returns only the providers that have been registered in the current binary. This ensures that CLI help text (`--help`) and flag validation accurately reflect the capabilities of the specific build. 4. Configurable Default Provider: The `DefaultCloudProvider` is no longer a hardcoded constant. It can now be set dynamically via the registry, allowing custom builds to define their own default provider without modifying core code. 5. Modular Build Support: The set of supported providers in a binary is now entirely controlled by blank imports (e.g., in `main.go`). While standard builds continue to include all providers, this pattern enables the easy creation of optimized, provider-specific binaries. Impact: This change significantly improves the maintainability and extensibility of the Cluster Autoscaler. It paves the way for a more modular architecture where cloud providers can be treated as optional plugins, reducing the core's dependency footprint and making it easier for the community to contribute and maintain provider-specific logic.
1 parent 9174111 commit 70fc12e

69 files changed

Lines changed: 396 additions & 1543 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cluster-autoscaler/cloudprovider/alicloud/alicloud_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@ import (
2424
apiv1 "k8s.io/api/core/v1"
2525
"k8s.io/apimachinery/pkg/api/resource"
2626
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
27+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2728
"k8s.io/autoscaler/cluster-autoscaler/config/dynamic"
2829
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
2930
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3031
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
32+
"k8s.io/client-go/informers"
3133
klog "k8s.io/klog/v2"
3234
)
3335

36+
func init() {
37+
builder.RegisterCloudProvider(cloudprovider.AlicloudProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
38+
return BuildAlicloud(opts, do, rl)
39+
})
40+
}
41+
3442
const (
3543
// GPULabel is the label added to nodes with GPU resource.
3644
GPULabel = "aliyun.accelerator/nvidia_name"

cluster-autoscaler/cloudprovider/aws/aws_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,22 @@ import (
2626
apiv1 "k8s.io/api/core/v1"
2727
"k8s.io/apimachinery/pkg/api/resource"
2828
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
29+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2930
"k8s.io/autoscaler/cluster-autoscaler/config"
3031
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
3132
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
3233
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3334
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
35+
"k8s.io/client-go/informers"
3436
klog "k8s.io/klog/v2"
3537
)
3638

39+
func init() {
40+
builder.RegisterCloudProvider(cloudprovider.AwsProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
41+
return BuildAWS(opts, do, rl)
42+
})
43+
}
44+
3745
const (
3846
// GPULabel is the label added to nodes with GPU resource.
3947
GPULabel = "k8s.amazonaws.com/accelerator"

cluster-autoscaler/cloudprovider/azure/azure_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,20 @@ import (
2525
apiv1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/resource"
2727
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
28+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2829
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
2930
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3031
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
32+
"k8s.io/client-go/informers"
3133
klog "k8s.io/klog/v2"
3234
)
3335

36+
func init() {
37+
builder.RegisterCloudProvider(cloudprovider.AzureProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
38+
return BuildAzure(opts, do, rl)
39+
})
40+
}
41+
3442
const (
3543
// GPULabel is the label added to nodes with GPU resource.
3644
GPULabel = AKSLabelKeyPrefixValue + "accelerator"

cluster-autoscaler/cloudprovider/baiducloud/baiducloud_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@ import (
2525
apiv1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/resource"
2727
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
28+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2829
"k8s.io/autoscaler/cluster-autoscaler/config"
2930
"k8s.io/autoscaler/cluster-autoscaler/config/dynamic"
3031
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
3132
"k8s.io/autoscaler/cluster-autoscaler/simulator/framework"
3233
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3334
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
35+
"k8s.io/client-go/informers"
3436
klog "k8s.io/klog/v2"
3537
)
3638

39+
func init() {
40+
builder.RegisterCloudProvider(cloudprovider.BaiducloudProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
41+
return BuildBaiducloud(opts, do, rl)
42+
})
43+
}
44+
3745
const (
3846
// GPULabel is the label added to nodes with GPU resource.
3947
GPULabel = "baidu/nvidia_name"

cluster-autoscaler/cloudprovider/bizflycloud/bizflycloud_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,20 @@ import (
2525
apiv1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/resource"
2727
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
28+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2829
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
2930
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3031
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
32+
"k8s.io/client-go/informers"
3133
klog "k8s.io/klog/v2"
3234
)
3335

36+
func init() {
37+
builder.RegisterCloudProvider(cloudprovider.BizflyCloudProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
38+
return BuildBizflyCloud(opts, do, rl)
39+
})
40+
}
41+
3442
var _ cloudprovider.CloudProvider = (*bizflycloudCloudProvider)(nil)
3543

3644
const (

cluster-autoscaler/cloudprovider/brightbox/brightbox_cloud_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@ import (
2525
apiv1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/resource"
2727
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
28+
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/builder"
2829
brightbox "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/brightbox/gobrightbox"
2930
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/brightbox/gobrightbox/status"
3031
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/brightbox/k8ssdk"
3132
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
3233
"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
3334
"k8s.io/autoscaler/cluster-autoscaler/utils/gpu"
35+
"k8s.io/client-go/informers"
3436
klog "k8s.io/klog/v2"
3537
)
3638

39+
func init() {
40+
builder.RegisterCloudProvider(cloudprovider.BrightboxProviderName, func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
41+
return BuildBrightbox(opts, do, rl)
42+
})
43+
}
44+
3745
const (
3846
// GPULabel is added to nodes with GPU resource
3947
GPULabel = "cloud.brightbox.com/gpu-node"

cluster-autoscaler/cloudprovider/builder/builder_alicloud.go

Lines changed: 0 additions & 44 deletions
This file was deleted.
Lines changed: 56 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
//go:build !gce && !aws && !azure && !kubemark && !alicloud && !magnum && !digitalocean && !clusterapi && !huaweicloud && !ionoscloud && !linode && !hetzner && !bizflycloud && !brightbox && !equinixmetal && !oci && !vultr && !tencentcloud && !scaleway && !externalgrpc && !civo && !rancher && !volcengine && !baiducloud && !cherry && !cloudstack && !exoscale && !kamatera && !ovhcloud && !kwok && !utho && !coreweave
2-
// +build !gce,!aws,!azure,!kubemark,!alicloud,!magnum,!digitalocean,!clusterapi,!huaweicloud,!ionoscloud,!linode,!hetzner,!bizflycloud,!brightbox,!equinixmetal,!oci,!vultr,!tencentcloud,!scaleway,!externalgrpc,!civo,!rancher,!volcengine,!baiducloud,!cherry,!cloudstack,!exoscale,!kamatera,!ovhcloud,!kwok,!utho,!coreweave
3-
41
/*
52
Copyright 2018 The Kubernetes Authors.
63
@@ -20,147 +17,74 @@ limitations under the License.
2017
package builder
2118

2219
import (
20+
"sort"
21+
2322
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
24-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/alicloud"
25-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/aws"
26-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/azure"
27-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/baiducloud"
28-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/bizflycloud"
29-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/brightbox"
30-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/cherryservers"
31-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/civo"
32-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/cloudstack"
33-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/clusterapi"
34-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/coreweave"
35-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/digitalocean"
36-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/equinixmetal"
37-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/exoscale"
38-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/externalgrpc"
39-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/gce"
40-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/hetzner"
41-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/huaweicloud"
42-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/ionoscloud"
43-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/kamatera"
44-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/kwok"
45-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/linode"
46-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/magnum"
47-
oci "k8s.io/autoscaler/cluster-autoscaler/cloudprovider/oci/instancepools"
48-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/ovhcloud"
49-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/rancher"
50-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/scaleway"
51-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/tencentcloud"
52-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/utho"
53-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/volcengine"
54-
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider/vultr"
5523
coreoptions "k8s.io/autoscaler/cluster-autoscaler/core/options"
5624
"k8s.io/client-go/informers"
25+
"k8s.io/klog/v2"
26+
)
27+
28+
// CloudProviderBuilder builds a cloud provider from provided parameters.
29+
type CloudProviderBuilder func(opts *coreoptions.AutoscalerOptions, do cloudprovider.NodeGroupDiscoveryOptions, rl *cloudprovider.ResourceLimiter, informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider
30+
31+
var (
32+
cloudProviderBuilders = make(map[string]CloudProviderBuilder)
33+
defaultCloudProvider string
5734
)
5835

59-
// AvailableCloudProviders supported by the cloud provider builder.
60-
var AvailableCloudProviders = []string{
61-
cloudprovider.AwsProviderName,
62-
cloudprovider.AzureProviderName,
63-
cloudprovider.GceProviderName,
64-
cloudprovider.AlicloudProviderName,
65-
cloudprovider.CherryServersProviderName,
66-
cloudprovider.CloudStackProviderName,
67-
cloudprovider.BaiducloudProviderName,
68-
cloudprovider.MagnumProviderName,
69-
cloudprovider.DigitalOceanProviderName,
70-
cloudprovider.ExoscaleProviderName,
71-
cloudprovider.ExternalGrpcProviderName,
72-
cloudprovider.HuaweicloudProviderName,
73-
cloudprovider.HetznerProviderName,
74-
cloudprovider.OracleCloudProviderName,
75-
cloudprovider.OVHcloudProviderName,
76-
cloudprovider.ClusterAPIProviderName,
77-
cloudprovider.IonoscloudProviderName,
78-
cloudprovider.KamateraProviderName,
79-
cloudprovider.KwokProviderName,
80-
cloudprovider.LinodeProviderName,
81-
cloudprovider.BizflyCloudProviderName,
82-
cloudprovider.BrightboxProviderName,
83-
cloudprovider.EquinixMetalProviderName,
84-
cloudprovider.VultrProviderName,
85-
cloudprovider.TencentcloudProviderName,
86-
cloudprovider.CivoProviderName,
87-
cloudprovider.ScalewayProviderName,
88-
cloudprovider.RancherProviderName,
89-
cloudprovider.VolcengineProviderName,
90-
cloudprovider.UthoProviderName,
91-
cloudprovider.CoreWeaveProviderName,
36+
// RegisterCloudProvider registers a cloud provider builder.
37+
func RegisterCloudProvider(name string, builder CloudProviderBuilder) {
38+
if _, ok := cloudProviderBuilders[name]; ok {
39+
klog.Fatalf("Cloud provider %s already registered", name)
40+
}
41+
cloudProviderBuilders[name] = builder
42+
}
43+
44+
// GetCloudProviderBuilder returns a cloud provider builder by name.
45+
func GetCloudProviderBuilder(name string) (CloudProviderBuilder, bool) {
46+
builder, ok := cloudProviderBuilders[name]
47+
return builder, ok
9248
}
9349

94-
// DefaultCloudProvider is GCE.
95-
const DefaultCloudProvider = cloudprovider.GceProviderName
50+
// AvailableCloudProviders returns the list of supported cloud providers.
51+
func AvailableCloudProviders() []string {
52+
providers := make([]string, 0, len(cloudProviderBuilders))
53+
for name := range cloudProviderBuilders {
54+
providers = append(providers, name)
55+
}
56+
sort.Strings(providers)
57+
return providers
58+
}
59+
60+
// SetDefaultCloudProvider sets the default cloud provider name.
61+
func SetDefaultCloudProvider(name string) {
62+
defaultCloudProvider = name
63+
}
64+
65+
// GetDefaultCloudProvider returns the default cloud provider name.
66+
func GetDefaultCloudProvider() string {
67+
return defaultCloudProvider
68+
}
69+
70+
// DefaultCloudProvider returns the default cloud provider name.
71+
func DefaultCloudProvider() string {
72+
if def := GetDefaultCloudProvider(); def != "" {
73+
return def
74+
}
75+
return cloudprovider.GceProviderName
76+
}
9677

78+
// buildCloudProvider creates a cloud provider instance using the registration registry.
79+
// This function is only used when no specific cloud provider build tag is set.
80+
// It requires that the desired cloud provider has been registered via its init() function,
81+
// which typically happens when the cloud provider's package is imported.
9782
func buildCloudProvider(opts *coreoptions.AutoscalerOptions,
9883
do cloudprovider.NodeGroupDiscoveryOptions,
9984
rl *cloudprovider.ResourceLimiter,
10085
informerFactory informers.SharedInformerFactory) cloudprovider.CloudProvider {
101-
switch opts.CloudProviderName {
102-
case cloudprovider.BizflyCloudProviderName:
103-
return bizflycloud.BuildBizflyCloud(opts, do, rl)
104-
case cloudprovider.GceProviderName:
105-
return gce.BuildGCE(opts, do, rl)
106-
case cloudprovider.AwsProviderName:
107-
return aws.BuildAWS(opts, do, rl)
108-
case cloudprovider.AzureProviderName:
109-
return azure.BuildAzure(opts, do, rl)
110-
case cloudprovider.AlicloudProviderName:
111-
return alicloud.BuildAlicloud(opts, do, rl)
112-
case cloudprovider.CherryServersProviderName:
113-
return cherryservers.BuildCherry(opts, do, rl)
114-
case cloudprovider.CloudStackProviderName:
115-
return cloudstack.BuildCloudStack(opts, do, rl)
116-
case cloudprovider.BaiducloudProviderName:
117-
return baiducloud.BuildBaiducloud(opts, do, rl)
118-
case cloudprovider.BrightboxProviderName:
119-
return brightbox.BuildBrightbox(opts, do, rl)
120-
case cloudprovider.DigitalOceanProviderName:
121-
return digitalocean.BuildDigitalOcean(opts, do, rl)
122-
case cloudprovider.ExoscaleProviderName:
123-
return exoscale.BuildExoscale(opts, do, rl)
124-
case cloudprovider.ExternalGrpcProviderName:
125-
return externalgrpc.BuildExternalGrpc(opts, do, rl)
126-
case cloudprovider.MagnumProviderName:
127-
return magnum.BuildMagnum(opts, do, rl)
128-
case cloudprovider.HuaweicloudProviderName:
129-
return huaweicloud.BuildHuaweiCloud(opts, do, rl)
130-
case cloudprovider.OVHcloudProviderName:
131-
return ovhcloud.BuildOVHcloud(opts, do, rl)
132-
case cloudprovider.HetznerProviderName:
133-
return hetzner.BuildHetzner(opts, do, rl)
134-
case cloudprovider.PacketProviderName, cloudprovider.EquinixMetalProviderName:
135-
return equinixmetal.BuildCloudProvider(opts, do, rl)
136-
case cloudprovider.ClusterAPIProviderName:
137-
return clusterapi.BuildClusterAPI(opts, do, rl)
138-
case cloudprovider.IonoscloudProviderName:
139-
return ionoscloud.BuildIonosCloud(opts, do, rl)
140-
case cloudprovider.KamateraProviderName:
141-
return kamatera.BuildKamatera(opts, do, rl)
142-
case cloudprovider.KwokProviderName:
143-
return kwok.BuildKwok(opts, do, rl, informerFactory)
144-
case cloudprovider.LinodeProviderName:
145-
return linode.BuildLinode(opts, do, rl)
146-
case cloudprovider.OracleCloudProviderName:
147-
return oci.BuildOCI(opts, do, rl)
148-
case cloudprovider.VultrProviderName:
149-
return vultr.BuildVultr(opts, do, rl)
150-
case cloudprovider.TencentcloudProviderName:
151-
return tencentcloud.BuildTencentcloud(opts, do, rl)
152-
case cloudprovider.CivoProviderName:
153-
return civo.BuildCivo(opts, do, rl)
154-
case cloudprovider.ScalewayProviderName:
155-
return scaleway.BuildScaleway(opts, do, rl)
156-
case cloudprovider.RancherProviderName:
157-
return rancher.BuildRancher(opts, do, rl)
158-
case cloudprovider.VolcengineProviderName:
159-
return volcengine.BuildVolcengine(opts, do, rl)
160-
case cloudprovider.UthoProviderName:
161-
return utho.BuildUtho(opts, do, rl)
162-
case cloudprovider.CoreWeaveProviderName:
163-
return coreweave.BuildCoreWeave(opts, do, rl)
86+
if builder, ok := GetCloudProviderBuilder(opts.CloudProviderName); ok {
87+
return builder(opts, do, rl, informerFactory)
16488
}
16589
return nil
16690
}

0 commit comments

Comments
 (0)