Skip to content

Commit cd9a701

Browse files
committed
Feat: Add support for GKETenantControllerManager
1 parent 3f017c9 commit cd9a701

File tree

20 files changed

+1529
-272
lines changed

20 files changed

+1529
-272
lines changed

cmd/cloud-controller-manager/gkenetworkparamsetcontroller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
networkinformers "github.com/GoogleCloudPlatform/gke-networking-api/client/network/informers/externalversions"
1111
cloudprovider "k8s.io/cloud-provider"
1212
gkenetworkparamsetcontroller "k8s.io/cloud-provider-gcp/pkg/controller/gkenetworkparamset"
13+
nodeipam "k8s.io/cloud-provider-gcp/pkg/controller/nodeipam"
1314
"k8s.io/cloud-provider-gcp/pkg/controller/nodeipam/ipam"
1415
"k8s.io/cloud-provider-gcp/providers/gce"
1516
"k8s.io/cloud-provider/app"
@@ -73,7 +74,7 @@ func startGkeNetworkParamsController(ccmConfig *cloudcontrollerconfig.CompletedC
7374
// with stack type and returns a list of typed cidrs and error
7475
func validClusterCIDR(clusterCIDRFromFlag string) ([]*net.IPNet, error) {
7576
// failure: bad cidrs in config
76-
clusterCIDRs, dualStack, err := processCIDRs(clusterCIDRFromFlag)
77+
clusterCIDRs, dualStack, err := nodeipam.ProcessCIDRs(clusterCIDRFromFlag)
7778
if err != nil {
7879
return nil, err
7980
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
providerconfigv1 "github.com/GoogleCloudPlatform/gke-enterprise-mt/apis/providerconfig/v1"
8+
"github.com/GoogleCloudPlatform/gke-enterprise-mt/pkg/framework"
9+
networkclientset "github.com/GoogleCloudPlatform/gke-networking-api/client/network/clientset/versioned"
10+
networkinformers "github.com/GoogleCloudPlatform/gke-networking-api/client/network/informers/externalversions"
11+
topologyclientset "github.com/GoogleCloudPlatform/gke-networking-api/client/nodetopology/clientset/versioned"
12+
"k8s.io/apimachinery/pkg/runtime/schema"
13+
"k8s.io/client-go/dynamic"
14+
dynamicinformer "k8s.io/client-go/dynamic/dynamicinformer"
15+
cloudprovider "k8s.io/cloud-provider"
16+
nodeipamcontrolleroptions "k8s.io/cloud-provider-gcp/cmd/cloud-controller-manager/options"
17+
"k8s.io/cloud-provider-gcp/pkg/controller/gketenantcontrollers"
18+
nodeipamconfig "k8s.io/cloud-provider-gcp/pkg/controller/nodeipam/config"
19+
"k8s.io/cloud-provider/app"
20+
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
21+
controllermanagerapp "k8s.io/controller-manager/app"
22+
"k8s.io/controller-manager/controller"
23+
"k8s.io/klog/v2"
24+
25+
"k8s.io/cloud-provider-gcp/pkg/controller/nodeipam"
26+
"k8s.io/cloud-provider-gcp/pkg/controller/nodeipam/ipam"
27+
"k8s.io/cloud-provider/controllers/node"
28+
"k8s.io/cloud-provider/controllers/nodelifecycle"
29+
)
30+
31+
// startGKETenantControllerManagerWrapper is used to take cloud config as input and start the GKE TenantControllerManager controller
32+
func startGKETenantControllerManagerWrapper(initContext app.ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface, nodeIPAMControllerOptions nodeipamcontrolleroptions.NodeIPAMControllerOptions) app.InitFunc {
33+
return func(ctx context.Context, controllerContext controllermanagerapp.ControllerContext) (controller.Interface, bool, error) {
34+
return startGKETenantControllerManager(ctx, initContext, controllerContext, completedConfig, cloud, *nodeIPAMControllerOptions.NodeIPAMControllerConfiguration)
35+
}
36+
}
37+
38+
func startGKETenantControllerManager(ctx context.Context, initContext app.ControllerInitContext, controlexContext controllermanagerapp.ControllerContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface, nodeIPAMConfig nodeipamconfig.NodeIPAMControllerConfiguration) (controller.Interface, bool, error) {
39+
if !enableProviderConfigController {
40+
klog.Infof("GKE Tenant Controller Manager is disabled (enable with --enable-provider-config-controller)")
41+
return nil, false, nil
42+
}
43+
44+
clientConfig := completedConfig.Kubeconfig
45+
46+
// Create network clients and informers
47+
networkClient, err := networkclientset.NewForConfig(clientConfig)
48+
if err != nil {
49+
klog.Errorf("Failed to create network client: %v", err)
50+
return nil, false, err
51+
}
52+
networkInformerFactory := networkinformers.NewSharedInformerFactory(networkClient, 12*time.Hour)
53+
networkInformer := networkInformerFactory.Networking().V1().Networks()
54+
gnpInformer := networkInformerFactory.Networking().V1().GKENetworkParamSets()
55+
56+
// Create topology client
57+
nodeTopologyClient, err := topologyclientset.NewForConfig(clientConfig)
58+
if err != nil {
59+
klog.Errorf("Failed to create topology client: %v", err)
60+
return nil, false, err
61+
}
62+
63+
// Create dynamic client for framework
64+
dynamicClient, err := dynamic.NewForConfig(clientConfig)
65+
if err != nil {
66+
klog.Errorf("Failed to create dynamic client: %v", err)
67+
return nil, false, err
68+
}
69+
70+
// Create dynamic informer factory for ProviderConfig
71+
gvr := schema.GroupVersionResource{
72+
Group: providerconfigv1.GroupName,
73+
Version: providerconfigv1.SchemeGroupVersion.Version,
74+
Resource: "providerconfigs",
75+
}
76+
dynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 12*time.Hour)
77+
providerConfigInformer := dynamicInformerFactory.ForResource(gvr).Informer()
78+
79+
// Define controllers
80+
controllers := map[string]gketenantcontrollers.ControllerStartFunc{
81+
"node-controller": func(cfg *gketenantcontrollers.ControllerConfig) error {
82+
klog.Infof("Creating OSS Cloud Node Controller for %s...", cfg.ProviderConfig.Name)
83+
nodeController, err := node.NewCloudNodeController(
84+
cfg.NodeInformer,
85+
cfg.KubeClient,
86+
cfg.Cloud,
87+
completedConfig.ComponentConfig.NodeStatusUpdateFrequency.Duration,
88+
completedConfig.ComponentConfig.NodeController.ConcurrentNodeSyncs,
89+
)
90+
if err != nil {
91+
return err
92+
}
93+
klog.Infof("Starting OSS Cloud Node Controller for %s (blocking)", cfg.ProviderConfig.Name)
94+
nodeController.Run(cfg.Context.Done(), cfg.ControllerContext.ControllerManagerMetrics)
95+
return nil
96+
},
97+
"node-ipam-controller": func(cfg *gketenantcontrollers.ControllerConfig) error {
98+
klog.Infof("Starting Node IPAM Controller for %s...", cfg.ProviderConfig.Name)
99+
clusterCIDR, err := gketenantcontrollers.GetClusterCIDRsFromProviderConfig(cfg.ProviderConfig)
100+
if err != nil {
101+
klog.Errorf("Failed to get ClusterCIDRs from ProviderConfig: %v. Node IPAM Controller will be disabled.", err)
102+
return nil // Don't fail the whole start
103+
}
104+
105+
_, started, err := nodeipam.StartNodeIpamController(
106+
cfg.Context,
107+
cfg.NodeInformer,
108+
cfg.KubeClient,
109+
cfg.Cloud,
110+
clusterCIDR,
111+
completedConfig.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs,
112+
nodeIPAMConfig.ServiceCIDR,
113+
nodeIPAMConfig.SecondaryServiceCIDR,
114+
nodeIPAMConfig,
115+
networkInformer,
116+
gnpInformer,
117+
nodeTopologyClient,
118+
ipam.CIDRAllocatorType(completedConfig.ComponentConfig.KubeCloudShared.CIDRAllocatorType),
119+
cfg.ControllerContext.ControllerManagerMetrics,
120+
)
121+
if err != nil {
122+
return err
123+
}
124+
if !started {
125+
klog.Infof("Node IPAM Controller not started (disabled in config) for %s", cfg.ProviderConfig.Name)
126+
} else {
127+
klog.Infof("Node IPAM Controller started with ClusterCIDR: %s for %s", clusterCIDR, cfg.ProviderConfig.Name)
128+
}
129+
// Block until context is canceled so starter doesn't exit early
130+
<-cfg.Context.Done()
131+
return nil
132+
},
133+
"node-lifecycle-controller": func(cfg *gketenantcontrollers.ControllerConfig) error {
134+
klog.Infof("Creating Node Lifecycle Controller for %s...", cfg.ProviderConfig.Name)
135+
nodeMonitorPeriod := completedConfig.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration
136+
lifecycleController, err := nodelifecycle.NewCloudNodeLifecycleController(
137+
cfg.NodeInformer,
138+
cfg.KubeClient,
139+
cfg.Cloud,
140+
nodeMonitorPeriod,
141+
)
142+
if err != nil {
143+
return err
144+
}
145+
klog.Infof("Starting Node Lifecycle Controller for %s...", cfg.ProviderConfig.Name)
146+
lifecycleController.Run(cfg.Context, cfg.ControllerContext.ControllerManagerMetrics)
147+
return nil
148+
},
149+
}
150+
151+
// Create the starter
152+
starter := gketenantcontrollers.NewNodeControllerStarter(
153+
completedConfig.ClientBuilder,
154+
completedConfig.ClientBuilder.ClientOrDie(initContext.ClientName),
155+
controlexContext.InformerFactory,
156+
completedConfig,
157+
controlexContext,
158+
controllers,
159+
)
160+
161+
// Create the framework manager
162+
mgr := framework.New(
163+
dynamicClient,
164+
providerConfigInformer,
165+
gkeTenantControllerManagerName,
166+
starter,
167+
ctx.Done(),
168+
)
169+
170+
// Start network informers
171+
networkInformerFactory.Start(ctx.Done())
172+
// Start dynamic informers
173+
dynamicInformerFactory.Start(ctx.Done())
174+
175+
// Run the manager
176+
go mgr.Run()
177+
178+
return nil, true, nil
179+
}

cmd/cloud-controller-manager/main.go

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ import (
2828
"k8s.io/apimachinery/pkg/util/wait"
2929
cloudprovider "k8s.io/cloud-provider"
3030
"k8s.io/cloud-provider-gcp/providers/gce"
31-
_ "k8s.io/cloud-provider-gcp/providers/gce"
31+
3232
"k8s.io/cloud-provider/app"
33-
"k8s.io/cloud-provider/app/config"
33+
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
3434
"k8s.io/cloud-provider/names"
3535
"k8s.io/cloud-provider/options"
3636
cliflag "k8s.io/component-base/cli/flag"
@@ -45,15 +45,11 @@ const (
4545
gkeServiceLBControllerName = "gke-service-lb-controller"
4646
gkeServiceControllerClientName = "gke-service-controller"
4747
gkeServiceAlias = "gke-service"
48+
gkeTenantControllerManagerName = "gke-tenant-controller-manager"
49+
gkeTenantControllerClientName = "gke-tenant-controller-manager"
50+
gkeTenantControllerManagerAlias = "gke-tenant-controller-manager"
4851
)
4952

50-
// enableMultiProject is bound to a command-line flag. When true, it enables the
51-
// projectFromNodeProviderID option of the GCE cloud provider, instructing it to
52-
// use the project specified in the Node's providerID for GCE API calls.
53-
//
54-
// This flag should only be enabled when the Node's providerID can be fully
55-
// trusted.
56-
//
5753
// Flag binding occurs in main()
5854
var enableMultiProject bool
5955

@@ -72,6 +68,9 @@ var enableRBSDefaultForL4NetLB bool
7268
// for L4 Load Balancers services
7369
var enableL4LBAnnotations bool
7470

71+
// enableProviderConfigController enables the gke-tenant-controller-manager.
72+
var enableProviderConfigController bool
73+
7574
func main() {
7675
rand.Seed(time.Now().UnixNano())
7776

@@ -91,6 +90,7 @@ func main() {
9190
cloudProviderFS.BoolVar(&enableDiscretePortForwarding, "enable-discrete-port-forwarding", false, "Enables forwarding of individual ports instead of port ranges for GCE external load balancers.")
9291
cloudProviderFS.BoolVar(&enableRBSDefaultForL4NetLB, "enable-rbs-default-l4-netlb", false, "Enables RBS defaulting for GCE L4 NetLB")
9392
cloudProviderFS.BoolVar(&enableL4LBAnnotations, "enable-l4-lb-annotations", false, "Enables Annotations for GCE L4 LB Services")
93+
cloudProviderFS.BoolVar(&enableProviderConfigController, "enable-provider-config-controller", false, "Enables the GKE Tenant Controller Manager for Multi-Tenancy.")
9494

9595
// add new controllers and initializers
9696
nodeIpamController := nodeIPAMController{}
@@ -111,12 +111,26 @@ func main() {
111111
Constructor: startGkeServiceControllerWrapper,
112112
}
113113

114+
controllerInitializers[gkeTenantControllerManagerName] = app.ControllerInitFuncConstructor{
115+
InitContext: app.ControllerInitContext{
116+
ClientName: gkeTenantControllerClientName,
117+
},
118+
Constructor: func(initContext app.ControllerInitContext, completedConfig *cloudcontrollerconfig.CompletedConfig, cloud cloudprovider.Interface) app.InitFunc {
119+
return startGKETenantControllerManagerWrapper(initContext, completedConfig, cloud, nodeIpamController.nodeIPAMControllerOptions)
120+
},
121+
}
122+
114123
// add controllers disabled by default
115124
app.ControllersDisabledByDefault.Insert("gkenetworkparamset")
116125
app.ControllersDisabledByDefault.Insert(gkeServiceLBControllerName)
126+
app.ControllersDisabledByDefault.Insert(gkeTenantControllerManagerName)
127+
128+
117129
aliasMap := names.CCMControllerAliases()
118130
aliasMap["nodeipam"] = kcmnames.NodeIpamController
119131
aliasMap[gkeServiceAlias] = gkeServiceLBControllerName
132+
aliasMap[gkeTenantControllerManagerAlias] = gkeTenantControllerManagerName
133+
120134
command := app.NewCloudControllerManagerCommand(ccmOptions, cloudInitializer, controllerInitializers, aliasMap, fss, wait.NeverStop)
121135

122136
logs.InitLogs()
@@ -127,7 +141,7 @@ func main() {
127141
}
128142
}
129143

130-
func cloudInitializer(config *config.CompletedConfig) cloudprovider.Interface {
144+
func cloudInitializer(config *cloudcontrollerconfig.CompletedConfig) cloudprovider.Interface {
131145
cloudConfig := config.ComponentConfig.KubeCloudShared.CloudProvider
132146

133147
// initialize cloud provider with the cloud provider name and config file provided
@@ -147,46 +161,28 @@ func cloudInitializer(config *config.CompletedConfig) cloudprovider.Interface {
147161
}
148162
}
149163

150-
if enableMultiProject {
164+
if enableMultiProject || enableDiscretePortForwarding || enableRBSDefaultForL4NetLB || enableL4LBAnnotations {
151165
gceCloud, ok := (cloud).(*gce.Cloud)
152166
if !ok {
153-
// Fail-fast: If enableMultiProject is set, the cloud provider MUST
154-
// be GCE. A non-GCE provider indicates a misconfiguration. Ideally,
155-
// we never expect this to be executed.
156-
klog.Fatalf("multi-project mode requires GCE cloud provider, but got %T", cloud)
167+
klog.Fatalf("One or more GCE-specific flags (enable-multi-project, enable-discrete-port-forwarding, enable-rbs-default-l4-netlb, enable-l4-lb-annotations) were set, but cloud provider is %T, not GCE.", cloud)
157168
}
158-
gceCloud.SetProjectFromNodeProviderID(true)
159-
}
160169

161-
if enableDiscretePortForwarding {
162-
gceCloud, ok := (cloud).(*gce.Cloud)
163-
if !ok {
164-
// Fail-fast: If enableDiscretePortForwarding is set, the cloud
165-
// provider MUST be GCE.
166-
klog.Fatalf("enable-discrete-port-forwarding requires GCE cloud provider, but got %T", cloud)
170+
if !enableProviderConfigController && enableMultiProject {
171+
gceCloud.SetProjectFromNodeProviderID(true)
167172
}
168-
gceCloud.SetEnableDiscretePortForwarding(true)
169-
}
170173

171-
if enableRBSDefaultForL4NetLB {
172-
gceCloud, ok := (cloud).(*gce.Cloud)
173-
if !ok {
174-
// Fail-fast: If enableRBSDefaultForL4NetLB is set, the cloud
175-
// provider MUST be GCE.
176-
klog.Fatalf("enable-rbs-default-l4-netlb requires GCE cloud provider, but got %T", cloud)
174+
if enableDiscretePortForwarding {
175+
gceCloud.SetEnableDiscretePortForwarding(true)
177176
}
178-
gceCloud.SetEnableRBSDefaultForL4NetLB(true)
179-
}
180177

181-
if enableL4LBAnnotations {
182-
gceCloud, ok := (cloud).(*gce.Cloud)
183-
if !ok {
184-
// Fail-fast: If enableL4LBAnnotations is set, the cloud
185-
// provider MUST be GCE.
186-
klog.Fatalf("enable-l4-lb-annotations requires GCE cloud provider, but got %T", cloud)
178+
if enableRBSDefaultForL4NetLB {
179+
gceCloud.SetEnableRBSDefaultForL4NetLB(true)
187180
}
188-
gceCloud.SetEnableL4LBAnnotations(true)
189-
}
190181

182+
if enableL4LBAnnotations {
183+
gceCloud.SetEnableL4LBAnnotations(true)
184+
}
185+
}
186+
191187
return cloud
192188
}

0 commit comments

Comments
 (0)