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  }