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