k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-controller-manager/app/core.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package app implements a server that runs a set of active 18 // components. This includes replication controllers, service endpoints and 19 // nodes. 20 package app 21 22 import ( 23 "context" 24 "errors" 25 "fmt" 26 "net" 27 "strings" 28 "time" 29 30 "k8s.io/klog/v2" 31 32 v1 "k8s.io/api/core/v1" 33 "k8s.io/apimachinery/pkg/runtime/schema" 34 genericfeatures "k8s.io/apiserver/pkg/features" 35 "k8s.io/apiserver/pkg/quota/v1/generic" 36 utilfeature "k8s.io/apiserver/pkg/util/feature" 37 clientset "k8s.io/client-go/kubernetes" 38 "k8s.io/client-go/metadata" 39 restclient "k8s.io/client-go/rest" 40 cloudnodelifecyclecontroller "k8s.io/cloud-provider/controllers/nodelifecycle" 41 routecontroller "k8s.io/cloud-provider/controllers/route" 42 servicecontroller "k8s.io/cloud-provider/controllers/service" 43 cpnames "k8s.io/cloud-provider/names" 44 "k8s.io/component-base/featuregate" 45 "k8s.io/controller-manager/controller" 46 csitrans "k8s.io/csi-translation-lib" 47 "k8s.io/kubernetes/cmd/kube-controller-manager/names" 48 pkgcontroller "k8s.io/kubernetes/pkg/controller" 49 endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint" 50 "k8s.io/kubernetes/pkg/controller/garbagecollector" 51 namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace" 52 nodeipamcontroller "k8s.io/kubernetes/pkg/controller/nodeipam" 53 nodeipamconfig "k8s.io/kubernetes/pkg/controller/nodeipam/config" 54 "k8s.io/kubernetes/pkg/controller/nodeipam/ipam" 55 lifecyclecontroller "k8s.io/kubernetes/pkg/controller/nodelifecycle" 56 "k8s.io/kubernetes/pkg/controller/podgc" 57 replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" 58 "k8s.io/kubernetes/pkg/controller/resourceclaim" 59 resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota" 60 serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount" 61 "k8s.io/kubernetes/pkg/controller/storageversiongc" 62 "k8s.io/kubernetes/pkg/controller/tainteviction" 63 ttlcontroller "k8s.io/kubernetes/pkg/controller/ttl" 64 "k8s.io/kubernetes/pkg/controller/ttlafterfinished" 65 "k8s.io/kubernetes/pkg/controller/volume/attachdetach" 66 "k8s.io/kubernetes/pkg/controller/volume/ephemeral" 67 "k8s.io/kubernetes/pkg/controller/volume/expand" 68 persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume" 69 "k8s.io/kubernetes/pkg/controller/volume/pvcprotection" 70 "k8s.io/kubernetes/pkg/controller/volume/pvprotection" 71 "k8s.io/kubernetes/pkg/features" 72 quotainstall "k8s.io/kubernetes/pkg/quota/v1/install" 73 "k8s.io/kubernetes/pkg/volume/csimigration" 74 "k8s.io/utils/clock" 75 netutils "k8s.io/utils/net" 76 ) 77 78 const ( 79 // defaultNodeMaskCIDRIPv4 is default mask size for IPv4 node cidr 80 defaultNodeMaskCIDRIPv4 = 24 81 // defaultNodeMaskCIDRIPv6 is default mask size for IPv6 node cidr 82 defaultNodeMaskCIDRIPv6 = 64 83 ) 84 85 func newServiceLBControllerDescriptor() *ControllerDescriptor { 86 return &ControllerDescriptor{ 87 name: cpnames.ServiceLBController, 88 aliases: []string{"service"}, 89 initFunc: startServiceLBController, 90 isCloudProviderController: true, 91 } 92 } 93 94 func startServiceLBController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 95 serviceController, err := servicecontroller.New( 96 controllerContext.Cloud, 97 controllerContext.ClientBuilder.ClientOrDie("service-controller"), 98 controllerContext.InformerFactory.Core().V1().Services(), 99 controllerContext.InformerFactory.Core().V1().Nodes(), 100 controllerContext.ComponentConfig.KubeCloudShared.ClusterName, 101 utilfeature.DefaultFeatureGate, 102 ) 103 if err != nil { 104 // This error shouldn't fail. It lives like this as a legacy. 105 klog.FromContext(ctx).Error(err, "Failed to start service controller") 106 return nil, false, nil 107 } 108 go serviceController.Run(ctx, int(controllerContext.ComponentConfig.ServiceController.ConcurrentServiceSyncs), controllerContext.ControllerManagerMetrics) 109 return nil, true, nil 110 } 111 func newNodeIpamControllerDescriptor() *ControllerDescriptor { 112 return &ControllerDescriptor{ 113 name: names.NodeIpamController, 114 aliases: []string{"nodeipam"}, 115 initFunc: startNodeIpamController, 116 } 117 } 118 119 func startNodeIpamController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 120 var serviceCIDR *net.IPNet 121 var secondaryServiceCIDR *net.IPNet 122 logger := klog.FromContext(ctx) 123 124 // should we start nodeIPAM 125 if !controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs { 126 return nil, false, nil 127 } 128 129 if controllerContext.ComponentConfig.KubeCloudShared.CIDRAllocatorType == string(ipam.CloudAllocatorType) { 130 // Cannot run cloud ipam controller if cloud provider is nil (--cloud-provider not set or set to 'external') 131 if controllerContext.Cloud == nil { 132 return nil, false, errors.New("--cidr-allocator-type is set to 'CloudAllocator' but cloud provider is not configured") 133 } 134 // As part of the removal of all the cloud providers from kubernetes, this support will be removed as well 135 klog.Warningf("DEPRECATED: 'CloudAllocator' bas been deprecated and will be removed in a future release.") 136 } 137 138 clusterCIDRs, err := validateCIDRs(controllerContext.ComponentConfig.KubeCloudShared.ClusterCIDR) 139 if err != nil { 140 return nil, false, err 141 } 142 143 // service cidr processing 144 if len(strings.TrimSpace(controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR)) != 0 { 145 _, serviceCIDR, err = netutils.ParseCIDRSloppy(controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR) 146 if err != nil { 147 logger.Info("Warning: unsuccessful parsing of service CIDR", "CIDR", controllerContext.ComponentConfig.NodeIPAMController.ServiceCIDR, "err", err) 148 } 149 } 150 151 if len(strings.TrimSpace(controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR)) != 0 { 152 _, secondaryServiceCIDR, err = netutils.ParseCIDRSloppy(controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR) 153 if err != nil { 154 logger.Info("Warning: unsuccessful parsing of service CIDR", "CIDR", controllerContext.ComponentConfig.NodeIPAMController.SecondaryServiceCIDR, "err", err) 155 } 156 } 157 158 // the following checks are triggered if both serviceCIDR and secondaryServiceCIDR are provided 159 if serviceCIDR != nil && secondaryServiceCIDR != nil { 160 // should be dual stack (from different IPFamilies) 161 dualstackServiceCIDR, err := netutils.IsDualStackCIDRs([]*net.IPNet{serviceCIDR, secondaryServiceCIDR}) 162 if err != nil { 163 return nil, false, fmt.Errorf("failed to perform dualstack check on serviceCIDR and secondaryServiceCIDR error:%v", err) 164 } 165 if !dualstackServiceCIDR { 166 return nil, false, fmt.Errorf("serviceCIDR and secondaryServiceCIDR are not dualstack (from different IPfamiles)") 167 } 168 } 169 170 // only --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 supported with dual stack clusters. 171 // --node-cidr-mask-size flag is incompatible with dual stack clusters. 172 nodeCIDRMaskSizes, err := setNodeCIDRMaskSizes(controllerContext.ComponentConfig.NodeIPAMController, clusterCIDRs) 173 if err != nil { 174 return nil, false, err 175 } 176 177 nodeIpamController, err := nodeipamcontroller.NewNodeIpamController( 178 ctx, 179 controllerContext.InformerFactory.Core().V1().Nodes(), 180 controllerContext.Cloud, 181 controllerContext.ClientBuilder.ClientOrDie("node-controller"), 182 clusterCIDRs, 183 serviceCIDR, 184 secondaryServiceCIDR, 185 nodeCIDRMaskSizes, 186 ipam.CIDRAllocatorType(controllerContext.ComponentConfig.KubeCloudShared.CIDRAllocatorType), 187 ) 188 if err != nil { 189 return nil, true, err 190 } 191 go nodeIpamController.RunWithMetrics(ctx, controllerContext.ControllerManagerMetrics) 192 return nil, true, nil 193 } 194 195 func newNodeLifecycleControllerDescriptor() *ControllerDescriptor { 196 return &ControllerDescriptor{ 197 name: names.NodeLifecycleController, 198 aliases: []string{"nodelifecycle"}, 199 initFunc: startNodeLifecycleController, 200 } 201 } 202 203 func startNodeLifecycleController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 204 lifecycleController, err := lifecyclecontroller.NewNodeLifecycleController( 205 ctx, 206 controllerContext.InformerFactory.Coordination().V1().Leases(), 207 controllerContext.InformerFactory.Core().V1().Pods(), 208 controllerContext.InformerFactory.Core().V1().Nodes(), 209 controllerContext.InformerFactory.Apps().V1().DaemonSets(), 210 // node lifecycle controller uses existing cluster role from node-controller 211 controllerContext.ClientBuilder.ClientOrDie("node-controller"), 212 controllerContext.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration, 213 controllerContext.ComponentConfig.NodeLifecycleController.NodeStartupGracePeriod.Duration, 214 controllerContext.ComponentConfig.NodeLifecycleController.NodeMonitorGracePeriod.Duration, 215 controllerContext.ComponentConfig.NodeLifecycleController.NodeEvictionRate, 216 controllerContext.ComponentConfig.NodeLifecycleController.SecondaryNodeEvictionRate, 217 controllerContext.ComponentConfig.NodeLifecycleController.LargeClusterSizeThreshold, 218 controllerContext.ComponentConfig.NodeLifecycleController.UnhealthyZoneThreshold, 219 ) 220 if err != nil { 221 return nil, true, err 222 } 223 go lifecycleController.Run(ctx) 224 return nil, true, nil 225 } 226 227 func newTaintEvictionControllerDescriptor() *ControllerDescriptor { 228 return &ControllerDescriptor{ 229 name: names.TaintEvictionController, 230 initFunc: startTaintEvictionController, 231 requiredFeatureGates: []featuregate.Feature{ 232 features.SeparateTaintEvictionController, 233 }, 234 } 235 } 236 237 func startTaintEvictionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 238 taintEvictionController, err := tainteviction.New( 239 ctx, 240 // taint-manager uses existing cluster role from node-controller 241 controllerContext.ClientBuilder.ClientOrDie("node-controller"), 242 controllerContext.InformerFactory.Core().V1().Pods(), 243 controllerContext.InformerFactory.Core().V1().Nodes(), 244 controllerName, 245 ) 246 if err != nil { 247 return nil, false, err 248 } 249 go taintEvictionController.Run(ctx) 250 return nil, true, nil 251 } 252 253 func newCloudNodeLifecycleControllerDescriptor() *ControllerDescriptor { 254 return &ControllerDescriptor{ 255 name: cpnames.CloudNodeLifecycleController, 256 aliases: []string{"cloud-node-lifecycle"}, 257 initFunc: startCloudNodeLifecycleController, 258 isCloudProviderController: true, 259 } 260 } 261 262 func startCloudNodeLifecycleController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 263 logger := klog.FromContext(ctx) 264 cloudNodeLifecycleController, err := cloudnodelifecyclecontroller.NewCloudNodeLifecycleController( 265 controllerContext.InformerFactory.Core().V1().Nodes(), 266 // cloud node lifecycle controller uses existing cluster role from node-controller 267 controllerContext.ClientBuilder.ClientOrDie("node-controller"), 268 controllerContext.Cloud, 269 controllerContext.ComponentConfig.KubeCloudShared.NodeMonitorPeriod.Duration, 270 ) 271 if err != nil { 272 // the controller manager should continue to run if the "Instances" interface is not 273 // supported, though it's unlikely for a cloud provider to not support it 274 logger.Error(err, "Failed to start cloud node lifecycle controller") 275 return nil, false, nil 276 } 277 278 go cloudNodeLifecycleController.Run(ctx, controllerContext.ControllerManagerMetrics) 279 return nil, true, nil 280 } 281 282 func newNodeRouteControllerDescriptor() *ControllerDescriptor { 283 return &ControllerDescriptor{ 284 name: cpnames.NodeRouteController, 285 aliases: []string{"route"}, 286 initFunc: startNodeRouteController, 287 isCloudProviderController: true, 288 } 289 } 290 291 func startNodeRouteController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 292 logger := klog.FromContext(ctx) 293 if !controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs || !controllerContext.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes { 294 logger.Info("Will not configure cloud provider routes for allocate-node-cidrs", "CIDRs", controllerContext.ComponentConfig.KubeCloudShared.AllocateNodeCIDRs, "routes", controllerContext.ComponentConfig.KubeCloudShared.ConfigureCloudRoutes) 295 return nil, false, nil 296 } 297 if controllerContext.Cloud == nil { 298 logger.Info("Warning: configure-cloud-routes is set, but no cloud provider specified. Will not configure cloud provider routes.") 299 return nil, false, nil 300 } 301 routes, ok := controllerContext.Cloud.Routes() 302 if !ok { 303 logger.Info("Warning: configure-cloud-routes is set, but cloud provider does not support routes. Will not configure cloud provider routes.") 304 return nil, false, nil 305 } 306 307 clusterCIDRs, err := validateCIDRs(controllerContext.ComponentConfig.KubeCloudShared.ClusterCIDR) 308 if err != nil { 309 return nil, false, err 310 } 311 312 routeController := routecontroller.New(routes, 313 controllerContext.ClientBuilder.ClientOrDie("route-controller"), 314 controllerContext.InformerFactory.Core().V1().Nodes(), 315 controllerContext.ComponentConfig.KubeCloudShared.ClusterName, 316 clusterCIDRs) 317 go routeController.Run(ctx, controllerContext.ComponentConfig.KubeCloudShared.RouteReconciliationPeriod.Duration, controllerContext.ControllerManagerMetrics) 318 return nil, true, nil 319 } 320 321 func newPersistentVolumeBinderControllerDescriptor() *ControllerDescriptor { 322 return &ControllerDescriptor{ 323 name: names.PersistentVolumeBinderController, 324 aliases: []string{"persistentvolume-binder"}, 325 initFunc: startPersistentVolumeBinderController, 326 } 327 } 328 329 func startPersistentVolumeBinderController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 330 logger := klog.FromContext(ctx) 331 plugins, err := ProbeControllerVolumePlugins(logger, controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration) 332 if err != nil { 333 return nil, true, fmt.Errorf("failed to probe volume plugins when starting persistentvolume controller: %v", err) 334 } 335 336 params := persistentvolumecontroller.ControllerParameters{ 337 KubeClient: controllerContext.ClientBuilder.ClientOrDie("persistent-volume-binder"), 338 SyncPeriod: controllerContext.ComponentConfig.PersistentVolumeBinderController.PVClaimBinderSyncPeriod.Duration, 339 VolumePlugins: plugins, 340 VolumeInformer: controllerContext.InformerFactory.Core().V1().PersistentVolumes(), 341 ClaimInformer: controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(), 342 ClassInformer: controllerContext.InformerFactory.Storage().V1().StorageClasses(), 343 PodInformer: controllerContext.InformerFactory.Core().V1().Pods(), 344 NodeInformer: controllerContext.InformerFactory.Core().V1().Nodes(), 345 EnableDynamicProvisioning: controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration.EnableDynamicProvisioning, 346 } 347 volumeController, volumeControllerErr := persistentvolumecontroller.NewController(ctx, params) 348 if volumeControllerErr != nil { 349 return nil, true, fmt.Errorf("failed to construct persistentvolume controller: %v", volumeControllerErr) 350 } 351 go volumeController.Run(ctx) 352 return nil, true, nil 353 } 354 355 func newPersistentVolumeAttachDetachControllerDescriptor() *ControllerDescriptor { 356 return &ControllerDescriptor{ 357 name: names.PersistentVolumeAttachDetachController, 358 aliases: []string{"attachdetach"}, 359 initFunc: startPersistentVolumeAttachDetachController, 360 } 361 } 362 363 func startPersistentVolumeAttachDetachController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 364 logger := klog.FromContext(ctx) 365 csiNodeInformer := controllerContext.InformerFactory.Storage().V1().CSINodes() 366 csiDriverInformer := controllerContext.InformerFactory.Storage().V1().CSIDrivers() 367 368 plugins, err := ProbeAttachableVolumePlugins(logger) 369 if err != nil { 370 return nil, true, fmt.Errorf("failed to probe volume plugins when starting attach/detach controller: %v", err) 371 } 372 373 ctx = klog.NewContext(ctx, logger) 374 attachDetachController, attachDetachControllerErr := 375 attachdetach.NewAttachDetachController( 376 ctx, 377 controllerContext.ClientBuilder.ClientOrDie("attachdetach-controller"), 378 controllerContext.InformerFactory.Core().V1().Pods(), 379 controllerContext.InformerFactory.Core().V1().Nodes(), 380 controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(), 381 controllerContext.InformerFactory.Core().V1().PersistentVolumes(), 382 csiNodeInformer, 383 csiDriverInformer, 384 controllerContext.InformerFactory.Storage().V1().VolumeAttachments(), 385 plugins, 386 GetDynamicPluginProber(controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration), 387 controllerContext.ComponentConfig.AttachDetachController.DisableAttachDetachReconcilerSync, 388 controllerContext.ComponentConfig.AttachDetachController.ReconcilerSyncLoopPeriod.Duration, 389 controllerContext.ComponentConfig.AttachDetachController.DisableForceDetachOnTimeout, 390 attachdetach.DefaultTimerConfig, 391 ) 392 if attachDetachControllerErr != nil { 393 return nil, true, fmt.Errorf("failed to start attach/detach controller: %v", attachDetachControllerErr) 394 } 395 go attachDetachController.Run(ctx) 396 return nil, true, nil 397 } 398 399 func newPersistentVolumeExpanderControllerDescriptor() *ControllerDescriptor { 400 return &ControllerDescriptor{ 401 name: names.PersistentVolumeExpanderController, 402 aliases: []string{"persistentvolume-expander"}, 403 initFunc: startPersistentVolumeExpanderController, 404 } 405 } 406 407 func startPersistentVolumeExpanderController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 408 logger := klog.FromContext(ctx) 409 plugins, err := ProbeExpandableVolumePlugins(logger, controllerContext.ComponentConfig.PersistentVolumeBinderController.VolumeConfiguration) 410 if err != nil { 411 return nil, true, fmt.Errorf("failed to probe volume plugins when starting volume expand controller: %v", err) 412 } 413 csiTranslator := csitrans.New() 414 415 expandController, expandControllerErr := expand.NewExpandController( 416 ctx, 417 controllerContext.ClientBuilder.ClientOrDie("expand-controller"), 418 controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(), 419 plugins, 420 csiTranslator, 421 csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate), 422 ) 423 424 if expandControllerErr != nil { 425 return nil, true, fmt.Errorf("failed to start volume expand controller: %v", expandControllerErr) 426 } 427 go expandController.Run(ctx) 428 return nil, true, nil 429 } 430 431 func newEphemeralVolumeControllerDescriptor() *ControllerDescriptor { 432 return &ControllerDescriptor{ 433 name: names.EphemeralVolumeController, 434 aliases: []string{"ephemeral-volume"}, 435 initFunc: startEphemeralVolumeController, 436 } 437 } 438 439 func startEphemeralVolumeController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 440 ephemeralController, err := ephemeral.NewController( 441 ctx, 442 controllerContext.ClientBuilder.ClientOrDie("ephemeral-volume-controller"), 443 controllerContext.InformerFactory.Core().V1().Pods(), 444 controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims()) 445 if err != nil { 446 return nil, true, fmt.Errorf("failed to start ephemeral volume controller: %v", err) 447 } 448 go ephemeralController.Run(ctx, int(controllerContext.ComponentConfig.EphemeralVolumeController.ConcurrentEphemeralVolumeSyncs)) 449 return nil, true, nil 450 } 451 452 const defaultResourceClaimControllerWorkers = 10 453 454 func newResourceClaimControllerDescriptor() *ControllerDescriptor { 455 return &ControllerDescriptor{ 456 name: names.ResourceClaimController, 457 aliases: []string{"resource-claim-controller"}, 458 initFunc: startResourceClaimController, 459 requiredFeatureGates: []featuregate.Feature{ 460 features.DynamicResourceAllocation, // TODO update app.TestFeatureGatedControllersShouldNotDefineAliases when removing this feature 461 }, 462 } 463 } 464 465 func startResourceClaimController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 466 ephemeralController, err := resourceclaim.NewController( 467 klog.FromContext(ctx), 468 controllerContext.ClientBuilder.ClientOrDie("resource-claim-controller"), 469 controllerContext.InformerFactory.Core().V1().Pods(), 470 controllerContext.InformerFactory.Resource().V1alpha2().PodSchedulingContexts(), 471 controllerContext.InformerFactory.Resource().V1alpha2().ResourceClaims(), 472 controllerContext.InformerFactory.Resource().V1alpha2().ResourceClaimTemplates()) 473 if err != nil { 474 return nil, true, fmt.Errorf("failed to start resource claim controller: %v", err) 475 } 476 go ephemeralController.Run(ctx, defaultResourceClaimControllerWorkers) 477 return nil, true, nil 478 } 479 480 func newEndpointsControllerDescriptor() *ControllerDescriptor { 481 return &ControllerDescriptor{ 482 name: names.EndpointsController, 483 aliases: []string{"endpoint"}, 484 initFunc: startEndpointsController, 485 } 486 } 487 488 func startEndpointsController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 489 go endpointcontroller.NewEndpointController( 490 ctx, 491 controllerContext.InformerFactory.Core().V1().Pods(), 492 controllerContext.InformerFactory.Core().V1().Services(), 493 controllerContext.InformerFactory.Core().V1().Endpoints(), 494 controllerContext.ClientBuilder.ClientOrDie("endpoint-controller"), 495 controllerContext.ComponentConfig.EndpointController.EndpointUpdatesBatchPeriod.Duration, 496 ).Run(ctx, int(controllerContext.ComponentConfig.EndpointController.ConcurrentEndpointSyncs)) 497 return nil, true, nil 498 } 499 500 func newReplicationControllerDescriptor() *ControllerDescriptor { 501 return &ControllerDescriptor{ 502 name: names.ReplicationControllerController, 503 aliases: []string{"replicationcontroller"}, 504 initFunc: startReplicationController, 505 } 506 } 507 508 func startReplicationController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 509 go replicationcontroller.NewReplicationManager( 510 ctx, 511 controllerContext.InformerFactory.Core().V1().Pods(), 512 controllerContext.InformerFactory.Core().V1().ReplicationControllers(), 513 controllerContext.ClientBuilder.ClientOrDie("replication-controller"), 514 replicationcontroller.BurstReplicas, 515 ).Run(ctx, int(controllerContext.ComponentConfig.ReplicationController.ConcurrentRCSyncs)) 516 return nil, true, nil 517 } 518 519 func newPodGarbageCollectorControllerDescriptor() *ControllerDescriptor { 520 return &ControllerDescriptor{ 521 name: names.PodGarbageCollectorController, 522 aliases: []string{"podgc"}, 523 initFunc: startPodGarbageCollectorController, 524 } 525 } 526 527 func startPodGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 528 go podgc.NewPodGC( 529 ctx, 530 controllerContext.ClientBuilder.ClientOrDie("pod-garbage-collector"), 531 controllerContext.InformerFactory.Core().V1().Pods(), 532 controllerContext.InformerFactory.Core().V1().Nodes(), 533 int(controllerContext.ComponentConfig.PodGCController.TerminatedPodGCThreshold), 534 ).Run(ctx) 535 return nil, true, nil 536 } 537 538 func newResourceQuotaControllerDescriptor() *ControllerDescriptor { 539 return &ControllerDescriptor{ 540 name: names.ResourceQuotaController, 541 aliases: []string{"resourcequota"}, 542 initFunc: startResourceQuotaController, 543 } 544 } 545 546 func startResourceQuotaController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 547 resourceQuotaControllerClient := controllerContext.ClientBuilder.ClientOrDie("resourcequota-controller") 548 resourceQuotaControllerDiscoveryClient := controllerContext.ClientBuilder.DiscoveryClientOrDie("resourcequota-controller") 549 discoveryFunc := resourceQuotaControllerDiscoveryClient.ServerPreferredNamespacedResources 550 listerFuncForResource := generic.ListerFuncForResourceFunc(controllerContext.InformerFactory.ForResource) 551 quotaConfiguration := quotainstall.NewQuotaConfigurationForControllers(listerFuncForResource) 552 553 resourceQuotaControllerOptions := &resourcequotacontroller.ControllerOptions{ 554 QuotaClient: resourceQuotaControllerClient.CoreV1(), 555 ResourceQuotaInformer: controllerContext.InformerFactory.Core().V1().ResourceQuotas(), 556 ResyncPeriod: pkgcontroller.StaticResyncPeriodFunc(controllerContext.ComponentConfig.ResourceQuotaController.ResourceQuotaSyncPeriod.Duration), 557 InformerFactory: controllerContext.ObjectOrMetadataInformerFactory, 558 ReplenishmentResyncPeriod: controllerContext.ResyncPeriod, 559 DiscoveryFunc: discoveryFunc, 560 IgnoredResourcesFunc: quotaConfiguration.IgnoredResources, 561 InformersStarted: controllerContext.InformersStarted, 562 Registry: generic.NewRegistry(quotaConfiguration.Evaluators()), 563 UpdateFilter: quotainstall.DefaultUpdateFilter(), 564 } 565 resourceQuotaController, err := resourcequotacontroller.NewController(ctx, resourceQuotaControllerOptions) 566 if err != nil { 567 return nil, false, err 568 } 569 go resourceQuotaController.Run(ctx, int(controllerContext.ComponentConfig.ResourceQuotaController.ConcurrentResourceQuotaSyncs)) 570 571 // Periodically the quota controller to detect new resource types 572 go resourceQuotaController.Sync(ctx, discoveryFunc, 30*time.Second) 573 574 return nil, true, nil 575 } 576 577 func newNamespaceControllerDescriptor() *ControllerDescriptor { 578 return &ControllerDescriptor{ 579 name: names.NamespaceController, 580 aliases: []string{"namespace"}, 581 initFunc: startNamespaceController, 582 } 583 } 584 585 func startNamespaceController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 586 // the namespace cleanup controller is very chatty. It makes lots of discovery calls and then it makes lots of delete calls 587 // the ratelimiter negatively affects its speed. Deleting 100 total items in a namespace (that's only a few of each resource 588 // including events), takes ~10 seconds by default. 589 nsKubeconfig := controllerContext.ClientBuilder.ConfigOrDie("namespace-controller") 590 nsKubeconfig.QPS *= 20 591 nsKubeconfig.Burst *= 100 592 namespaceKubeClient := clientset.NewForConfigOrDie(nsKubeconfig) 593 return startModifiedNamespaceController(ctx, controllerContext, namespaceKubeClient, nsKubeconfig) 594 } 595 596 func startModifiedNamespaceController(ctx context.Context, controllerContext ControllerContext, namespaceKubeClient clientset.Interface, nsKubeconfig *restclient.Config) (controller.Interface, bool, error) { 597 598 metadataClient, err := metadata.NewForConfig(nsKubeconfig) 599 if err != nil { 600 return nil, true, err 601 } 602 603 discoverResourcesFn := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources 604 605 namespaceController := namespacecontroller.NewNamespaceController( 606 ctx, 607 namespaceKubeClient, 608 metadataClient, 609 discoverResourcesFn, 610 controllerContext.InformerFactory.Core().V1().Namespaces(), 611 controllerContext.ComponentConfig.NamespaceController.NamespaceSyncPeriod.Duration, 612 v1.FinalizerKubernetes, 613 ) 614 go namespaceController.Run(ctx, int(controllerContext.ComponentConfig.NamespaceController.ConcurrentNamespaceSyncs)) 615 616 return nil, true, nil 617 } 618 619 func newServiceAccountControllerDescriptor() *ControllerDescriptor { 620 return &ControllerDescriptor{ 621 name: names.ServiceAccountController, 622 aliases: []string{"serviceaccount"}, 623 initFunc: startServiceAccountController, 624 } 625 } 626 627 func startServiceAccountController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 628 sac, err := serviceaccountcontroller.NewServiceAccountsController( 629 controllerContext.InformerFactory.Core().V1().ServiceAccounts(), 630 controllerContext.InformerFactory.Core().V1().Namespaces(), 631 controllerContext.ClientBuilder.ClientOrDie("service-account-controller"), 632 serviceaccountcontroller.DefaultServiceAccountsControllerOptions(), 633 ) 634 if err != nil { 635 return nil, true, fmt.Errorf("error creating ServiceAccount controller: %v", err) 636 } 637 go sac.Run(ctx, 1) 638 return nil, true, nil 639 } 640 641 func newTTLControllerDescriptor() *ControllerDescriptor { 642 return &ControllerDescriptor{ 643 name: names.TTLController, 644 aliases: []string{"ttl"}, 645 initFunc: startTTLController, 646 } 647 } 648 649 func startTTLController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 650 go ttlcontroller.NewTTLController( 651 ctx, 652 controllerContext.InformerFactory.Core().V1().Nodes(), 653 controllerContext.ClientBuilder.ClientOrDie("ttl-controller"), 654 ).Run(ctx, 5) 655 return nil, true, nil 656 } 657 658 func newGarbageCollectorControllerDescriptor() *ControllerDescriptor { 659 return &ControllerDescriptor{ 660 name: names.GarbageCollectorController, 661 aliases: []string{"garbagecollector"}, 662 initFunc: startGarbageCollectorController, 663 } 664 } 665 666 func startGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 667 if !controllerContext.ComponentConfig.GarbageCollectorController.EnableGarbageCollector { 668 return nil, false, nil 669 } 670 671 gcClientset := controllerContext.ClientBuilder.ClientOrDie("generic-garbage-collector") 672 discoveryClient := controllerContext.ClientBuilder.DiscoveryClientOrDie("generic-garbage-collector") 673 674 config := controllerContext.ClientBuilder.ConfigOrDie("generic-garbage-collector") 675 // Increase garbage collector controller's throughput: each object deletion takes two API calls, 676 // so to get |config.QPS| deletion rate we need to allow 2x more requests for this controller. 677 config.QPS *= 2 678 metadataClient, err := metadata.NewForConfig(config) 679 if err != nil { 680 return nil, true, err 681 } 682 683 ignoredResources := make(map[schema.GroupResource]struct{}) 684 for _, r := range controllerContext.ComponentConfig.GarbageCollectorController.GCIgnoredResources { 685 ignoredResources[schema.GroupResource{Group: r.Group, Resource: r.Resource}] = struct{}{} 686 } 687 688 garbageCollector, err := garbagecollector.NewComposedGarbageCollector( 689 ctx, 690 gcClientset, 691 metadataClient, 692 controllerContext.RESTMapper, 693 controllerContext.GraphBuilder, 694 ) 695 if err != nil { 696 return nil, true, fmt.Errorf("failed to start the generic garbage collector: %w", err) 697 } 698 699 // Start the garbage collector. 700 workers := int(controllerContext.ComponentConfig.GarbageCollectorController.ConcurrentGCSyncs) 701 go garbageCollector.Run(ctx, workers) 702 703 // Periodically refresh the RESTMapper with new discovery information and sync 704 // the garbage collector. 705 go garbageCollector.Sync(ctx, discoveryClient, 30*time.Second) 706 707 return garbageCollector, true, nil 708 } 709 710 func newPersistentVolumeClaimProtectionControllerDescriptor() *ControllerDescriptor { 711 return &ControllerDescriptor{ 712 name: names.PersistentVolumeClaimProtectionController, 713 aliases: []string{"pvc-protection"}, 714 initFunc: startPersistentVolumeClaimProtectionController, 715 } 716 } 717 718 func startPersistentVolumeClaimProtectionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 719 pvcProtectionController, err := pvcprotection.NewPVCProtectionController( 720 klog.FromContext(ctx), 721 controllerContext.InformerFactory.Core().V1().PersistentVolumeClaims(), 722 controllerContext.InformerFactory.Core().V1().Pods(), 723 controllerContext.ClientBuilder.ClientOrDie("pvc-protection-controller"), 724 ) 725 if err != nil { 726 return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err) 727 } 728 go pvcProtectionController.Run(ctx, 1) 729 return nil, true, nil 730 } 731 732 func newPersistentVolumeProtectionControllerDescriptor() *ControllerDescriptor { 733 return &ControllerDescriptor{ 734 name: names.PersistentVolumeProtectionController, 735 aliases: []string{"pv-protection"}, 736 initFunc: startPersistentVolumeProtectionController, 737 } 738 } 739 740 func startPersistentVolumeProtectionController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 741 go pvprotection.NewPVProtectionController( 742 klog.FromContext(ctx), 743 controllerContext.InformerFactory.Core().V1().PersistentVolumes(), 744 controllerContext.ClientBuilder.ClientOrDie("pv-protection-controller"), 745 ).Run(ctx, 1) 746 return nil, true, nil 747 } 748 749 func newTTLAfterFinishedControllerDescriptor() *ControllerDescriptor { 750 return &ControllerDescriptor{ 751 name: names.TTLAfterFinishedController, 752 aliases: []string{"ttl-after-finished"}, 753 initFunc: startTTLAfterFinishedController, 754 } 755 } 756 757 func startTTLAfterFinishedController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 758 go ttlafterfinished.New( 759 ctx, 760 controllerContext.InformerFactory.Batch().V1().Jobs(), 761 controllerContext.ClientBuilder.ClientOrDie("ttl-after-finished-controller"), 762 ).Run(ctx, int(controllerContext.ComponentConfig.TTLAfterFinishedController.ConcurrentTTLSyncs)) 763 return nil, true, nil 764 } 765 766 func newLegacyServiceAccountTokenCleanerControllerDescriptor() *ControllerDescriptor { 767 return &ControllerDescriptor{ 768 name: names.LegacyServiceAccountTokenCleanerController, 769 aliases: []string{"legacy-service-account-token-cleaner"}, 770 initFunc: startLegacyServiceAccountTokenCleanerController, 771 } 772 } 773 774 func startLegacyServiceAccountTokenCleanerController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 775 cleanUpPeriod := controllerContext.ComponentConfig.LegacySATokenCleaner.CleanUpPeriod.Duration 776 legacySATokenCleaner, err := serviceaccountcontroller.NewLegacySATokenCleaner( 777 controllerContext.InformerFactory.Core().V1().ServiceAccounts(), 778 controllerContext.InformerFactory.Core().V1().Secrets(), 779 controllerContext.InformerFactory.Core().V1().Pods(), 780 controllerContext.ClientBuilder.ClientOrDie("legacy-service-account-token-cleaner"), 781 clock.RealClock{}, 782 serviceaccountcontroller.LegacySATokenCleanerOptions{ 783 CleanUpPeriod: cleanUpPeriod, 784 SyncInterval: serviceaccountcontroller.DefaultCleanerSyncInterval, 785 }) 786 if err != nil { 787 return nil, true, fmt.Errorf("failed to start the legacy service account token cleaner: %v", err) 788 } 789 go legacySATokenCleaner.Run(ctx) 790 return nil, true, nil 791 } 792 793 // processCIDRs is a helper function that works on a comma separated cidrs and returns 794 // a list of typed cidrs 795 // error if failed to parse any of the cidrs or invalid length of cidrs 796 func validateCIDRs(cidrsList string) ([]*net.IPNet, error) { 797 // failure: bad cidrs in config 798 clusterCIDRs, dualStack, err := processCIDRs(cidrsList) 799 if err != nil { 800 return nil, err 801 } 802 803 // failure: more than one cidr but they are not configured as dual stack 804 if len(clusterCIDRs) > 1 && !dualStack { 805 return nil, fmt.Errorf("len of ClusterCIDRs==%v and they are not configured as dual stack (at least one from each IPFamily", len(clusterCIDRs)) 806 } 807 808 // failure: more than cidrs is not allowed even with dual stack 809 if len(clusterCIDRs) > 2 { 810 return nil, fmt.Errorf("length of clusterCIDRs is:%v more than max allowed of 2", len(clusterCIDRs)) 811 } 812 813 return clusterCIDRs, nil 814 } 815 816 // processCIDRs is a helper function that works on a comma separated cidrs and returns 817 // a list of typed cidrs 818 // a flag if cidrs represents a dual stack 819 // error if failed to parse any of the cidrs 820 func processCIDRs(cidrsList string) ([]*net.IPNet, bool, error) { 821 cidrsSplit := strings.Split(strings.TrimSpace(cidrsList), ",") 822 823 cidrs, err := netutils.ParseCIDRs(cidrsSplit) 824 if err != nil { 825 return nil, false, err 826 } 827 828 // if cidrs has an error then the previous call will fail 829 // safe to ignore error checking on next call 830 dualstack, _ := netutils.IsDualStackCIDRs(cidrs) 831 832 return cidrs, dualstack, nil 833 } 834 835 // setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes to the value provided 836 // for --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 respectively. If value not provided, 837 // then it will return default IPv4 and IPv6 cidr mask sizes. 838 func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration, clusterCIDRs []*net.IPNet) ([]int, error) { 839 840 sortedSizes := func(maskSizeIPv4, maskSizeIPv6 int) []int { 841 nodeMaskCIDRs := make([]int, len(clusterCIDRs)) 842 843 for idx, clusterCIDR := range clusterCIDRs { 844 if netutils.IsIPv6CIDR(clusterCIDR) { 845 nodeMaskCIDRs[idx] = maskSizeIPv6 846 } else { 847 nodeMaskCIDRs[idx] = maskSizeIPv4 848 } 849 } 850 return nodeMaskCIDRs 851 } 852 853 // --node-cidr-mask-size flag is incompatible with dual stack clusters. 854 ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6 855 isDualstack := len(clusterCIDRs) > 1 856 857 // case one: cluster is dualstack (i.e, more than one cidr) 858 if isDualstack { 859 // if --node-cidr-mask-size then fail, user must configure the correct dual-stack mask sizes (or use default) 860 if cfg.NodeCIDRMaskSize != 0 { 861 return nil, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters") 862 863 } 864 865 if cfg.NodeCIDRMaskSizeIPv4 != 0 { 866 ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4) 867 } 868 if cfg.NodeCIDRMaskSizeIPv6 != 0 { 869 ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6) 870 } 871 return sortedSizes(ipv4Mask, ipv6Mask), nil 872 } 873 874 maskConfigured := cfg.NodeCIDRMaskSize != 0 875 maskV4Configured := cfg.NodeCIDRMaskSizeIPv4 != 0 876 maskV6Configured := cfg.NodeCIDRMaskSizeIPv6 != 0 877 isSingleStackIPv6 := netutils.IsIPv6CIDR(clusterCIDRs[0]) 878 879 // original flag is set 880 if maskConfigured { 881 // original mask flag is still the main reference. 882 if maskV4Configured || maskV6Configured { 883 return nil, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags") 884 } 885 886 mask := int(cfg.NodeCIDRMaskSize) 887 return sortedSizes(mask, mask), nil 888 } 889 890 if maskV4Configured { 891 if isSingleStackIPv6 { 892 return nil, errors.New("usage of --node-cidr-mask-size-ipv4 is not allowed for a single-stack IPv6 cluster") 893 } 894 895 ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4) 896 } 897 898 // !maskV4Configured && !maskConfigured && maskV6Configured 899 if maskV6Configured { 900 if !isSingleStackIPv6 { 901 return nil, errors.New("usage of --node-cidr-mask-size-ipv6 is not allowed for a single-stack IPv4 cluster") 902 } 903 904 ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6) 905 } 906 return sortedSizes(ipv4Mask, ipv6Mask), nil 907 } 908 909 func newStorageVersionGarbageCollectorControllerDescriptor() *ControllerDescriptor { 910 return &ControllerDescriptor{ 911 name: names.StorageVersionGarbageCollectorController, 912 aliases: []string{"storage-version-gc"}, 913 initFunc: startStorageVersionGarbageCollectorController, 914 requiredFeatureGates: []featuregate.Feature{ 915 genericfeatures.APIServerIdentity, 916 genericfeatures.StorageVersionAPI, 917 }, 918 } 919 } 920 921 func startStorageVersionGarbageCollectorController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) { 922 go storageversiongc.NewStorageVersionGC( 923 ctx, 924 controllerContext.ClientBuilder.ClientOrDie("storage-version-garbage-collector"), 925 controllerContext.InformerFactory.Coordination().V1().Leases(), 926 controllerContext.InformerFactory.Internal().V1alpha1().StorageVersions(), 927 ).Run(ctx) 928 return nil, true, nil 929 }