@@ -40,8 +40,9 @@ import (
4040// ImagePrefetchReconciler reconciles a ImagePrefetch object
4141type ImagePrefetchReconciler struct {
4242 client.Client
43- Scheme * runtime.Scheme
44- ImagePullNodeLimit int
43+ Scheme * runtime.Scheme
44+ ImagePullNodeLimit int
45+ MaxConcurrentNodeImageSetCreations int
4546}
4647
4748// +kubebuilder:rbac:groups=ofen.cybozu.io,resources=imageprefetches,verbs=get;list;watch;create;update;patch;delete
@@ -273,8 +274,22 @@ func scoreNode(node corev1.Node, zoneCount map[string]int) int {
273274func (r * ImagePrefetchReconciler ) createOrUpdateNodeImageSet (ctx context.Context , imgPrefetch * ofenv1.ImagePrefetch , selectedNodes []string ) error {
274275 logger := log .FromContext (ctx )
275276
277+ var nodeImageSetList ofenv1.NodeImageSetList
278+ if err := r .List (ctx , & nodeImageSetList , client .MatchingLabels (map [string ]string {
279+ constants .OwnerImagePrefetchNamespace : imgPrefetch .Namespace ,
280+ constants .OwnerImagePrefetchName : imgPrefetch .Name ,
281+ })); err != nil {
282+ return fmt .Errorf ("failed to list NodeImageSets: %w" , err )
283+ }
284+
285+ maxNodeImageSetsToProcess := getMaxNodeImageSetsToCreate (nodeImageSetList , r .MaxConcurrentNodeImageSetCreations , len (selectedNodes ), imgPrefetch .Generation )
276286 selectNodes := map [string ]struct {}{}
277287 for i , nodeName := range selectedNodes {
288+ // Limit the number of NodeImageSets created or updated in one reconciliation loop
289+ if i >= maxNodeImageSetsToProcess {
290+ return nil
291+ }
292+
278293 selectNodes [nodeName ] = struct {}{}
279294 nodeImageSetName , err := getNodeImageSetName (imgPrefetch , nodeName )
280295 if err != nil {
@@ -308,8 +323,8 @@ func (r *ImagePrefetchReconciler) createOrUpdateNodeImageSet(ctx context.Context
308323 }
309324
310325 // Delete unnecessary NodeImageSets
311- nodeImageSetList := & ofenv1.NodeImageSetList {}
312- if err := r .List (ctx , nodeImageSetList , client .MatchingLabels (map [string ]string {
326+ nodeImageSetList = ofenv1.NodeImageSetList {}
327+ if err := r .List (ctx , & nodeImageSetList , client .MatchingLabels (map [string ]string {
313328 constants .OwnerImagePrefetchNamespace : imgPrefetch .Namespace ,
314329 constants .OwnerImagePrefetchName : imgPrefetch .Name ,
315330 })); err != nil {
@@ -333,6 +348,23 @@ func (r *ImagePrefetchReconciler) createOrUpdateNodeImageSet(ctx context.Context
333348 return nil
334349}
335350
351+ func getMaxNodeImageSetsToCreate (currentNodeImageSets ofenv1.NodeImageSetList , maxConcurrentNodeImageSetCreations int , desiredNodeImageSetsCount int , generation int64 ) int {
352+ var readyNodeImageSetsCount = 0
353+
354+ for _ , nodeImageSet := range currentNodeImageSets .Items {
355+ if meta .IsStatusConditionTrue (nodeImageSet .Status .Conditions , ofenv1 .ConditionImageAvailable ) &&
356+ nodeImageSet .Status .ImagePrefetchGeneration == generation &&
357+ len (nodeImageSet .Spec .Images ) == len (nodeImageSet .Status .ContainerImageStatuses ) {
358+ readyNodeImageSetsCount ++
359+ }
360+ }
361+
362+ if readyNodeImageSetsCount < desiredNodeImageSetsCount {
363+ return readyNodeImageSetsCount + maxConcurrentNodeImageSetCreations
364+ }
365+ return desiredNodeImageSetsCount
366+ }
367+
336368func (r * ImagePrefetchReconciler ) applyNodeImageSet (ctx context.Context , nodeImageSet * ofenv1apply.NodeImageSetApplyConfiguration , name string ) error {
337369 obj , err := runtime .DefaultUnstructuredConverter .ToUnstructured (nodeImageSet )
338370 if err != nil {
0 commit comments