k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controller/nodeipam/node_ipam_controller.go (about) 1 /* 2 Copyright 2014 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 nodeipam 18 19 import ( 20 "context" 21 "fmt" 22 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 23 coreinformers "k8s.io/client-go/informers/core/v1" 24 clientset "k8s.io/client-go/kubernetes" 25 v1core "k8s.io/client-go/kubernetes/typed/core/v1" 26 corelisters "k8s.io/client-go/listers/core/v1" 27 "k8s.io/client-go/tools/cache" 28 "k8s.io/client-go/tools/record" 29 cloudprovider "k8s.io/cloud-provider" 30 controllersmetrics "k8s.io/component-base/metrics/prometheus/controllers" 31 "k8s.io/klog/v2" 32 "k8s.io/kubernetes/pkg/controller/nodeipam/ipam" 33 "net" 34 ) 35 36 // ipamController is an interface abstracting an interface for 37 // legacy mode. It is needed to ensure correct building for 38 // both provider-specific and providerless environments. 39 type ipamController interface { 40 Run(ctx context.Context) 41 } 42 43 // Controller is the controller that manages node ipam state. 44 type Controller struct { 45 allocatorType ipam.CIDRAllocatorType 46 47 cloud cloudprovider.Interface 48 clusterCIDRs []*net.IPNet 49 serviceCIDR *net.IPNet 50 secondaryServiceCIDR *net.IPNet 51 kubeClient clientset.Interface 52 eventBroadcaster record.EventBroadcaster 53 54 nodeLister corelisters.NodeLister 55 nodeInformerSynced cache.InformerSynced 56 57 legacyIPAM ipamController 58 cidrAllocator ipam.CIDRAllocator 59 } 60 61 // NewNodeIpamController returns a new node IP Address Management controller to 62 // sync instances from cloudprovider. 63 // This method returns an error if it is unable to initialize the CIDR bitmap with 64 // podCIDRs it has already allocated to nodes. Since we don't allow podCIDR changes 65 // currently, this should be handled as a fatal error. 66 func NewNodeIpamController( 67 ctx context.Context, 68 nodeInformer coreinformers.NodeInformer, 69 cloud cloudprovider.Interface, 70 kubeClient clientset.Interface, 71 clusterCIDRs []*net.IPNet, 72 serviceCIDR *net.IPNet, 73 secondaryServiceCIDR *net.IPNet, 74 nodeCIDRMaskSizes []int, 75 allocatorType ipam.CIDRAllocatorType) (*Controller, error) { 76 77 if kubeClient == nil { 78 return nil, fmt.Errorf("kubeClient is nil when starting Controller") 79 } 80 81 // Cloud CIDR allocator does not rely on clusterCIDR or nodeCIDRMaskSize for allocation. 82 if allocatorType != ipam.CloudAllocatorType { 83 if len(clusterCIDRs) == 0 { 84 return nil, fmt.Errorf("Controller: Must specify --cluster-cidr if --allocate-node-cidrs is set") 85 } 86 87 for idx, cidr := range clusterCIDRs { 88 mask := cidr.Mask 89 if maskSize, _ := mask.Size(); maskSize > nodeCIDRMaskSizes[idx] { 90 return nil, fmt.Errorf("Controller: Invalid --cluster-cidr, mask size of cluster CIDR must be less than or equal to --node-cidr-mask-size configured for CIDR family") 91 } 92 } 93 } 94 95 ic := &Controller{ 96 cloud: cloud, 97 kubeClient: kubeClient, 98 eventBroadcaster: record.NewBroadcaster(record.WithContext(ctx)), 99 clusterCIDRs: clusterCIDRs, 100 serviceCIDR: serviceCIDR, 101 secondaryServiceCIDR: secondaryServiceCIDR, 102 allocatorType: allocatorType, 103 } 104 105 // TODO: Abstract this check into a generic controller manager should run method. 106 if ic.allocatorType == ipam.IPAMFromClusterAllocatorType || ic.allocatorType == ipam.IPAMFromCloudAllocatorType { 107 var err error 108 ic.legacyIPAM, err = createLegacyIPAM(ctx, ic, nodeInformer, cloud, kubeClient, clusterCIDRs, serviceCIDR, nodeCIDRMaskSizes) 109 if err != nil { 110 return nil, err 111 } 112 } else { 113 var err error 114 115 allocatorParams := ipam.CIDRAllocatorParams{ 116 ClusterCIDRs: clusterCIDRs, 117 ServiceCIDR: ic.serviceCIDR, 118 SecondaryServiceCIDR: ic.secondaryServiceCIDR, 119 NodeCIDRMaskSizes: nodeCIDRMaskSizes, 120 } 121 122 ic.cidrAllocator, err = ipam.New(ctx, kubeClient, cloud, nodeInformer, ic.allocatorType, allocatorParams) 123 if err != nil { 124 return nil, err 125 } 126 } 127 128 ic.nodeLister = nodeInformer.Lister() 129 ic.nodeInformerSynced = nodeInformer.Informer().HasSynced 130 131 return ic, nil 132 } 133 134 // Run starts an asynchronous loop that monitors the status of cluster nodes. 135 func (nc *Controller) Run(ctx context.Context) { 136 defer utilruntime.HandleCrash() 137 138 // Start event processing pipeline. 139 nc.eventBroadcaster.StartStructuredLogging(3) 140 nc.eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: nc.kubeClient.CoreV1().Events("")}) 141 defer nc.eventBroadcaster.Shutdown() 142 klog.FromContext(ctx).Info("Starting ipam controller") 143 defer klog.FromContext(ctx).Info("Shutting down ipam controller") 144 145 if !cache.WaitForNamedCacheSync("node", ctx.Done(), nc.nodeInformerSynced) { 146 return 147 } 148 149 if nc.allocatorType == ipam.IPAMFromClusterAllocatorType || nc.allocatorType == ipam.IPAMFromCloudAllocatorType { 150 go nc.legacyIPAM.Run(ctx) 151 } else { 152 go nc.cidrAllocator.Run(ctx) 153 } 154 155 <-ctx.Done() 156 } 157 158 // RunWithMetrics is a wrapper for Run that also tracks starting and stopping of the nodeipam controller with additional metric 159 func (nc *Controller) RunWithMetrics(ctx context.Context, controllerManagerMetrics *controllersmetrics.ControllerManagerMetrics) { 160 controllerManagerMetrics.ControllerStarted("nodeipam") 161 defer controllerManagerMetrics.ControllerStopped("nodeipam") 162 nc.Run(ctx) 163 }