k8s.io/kubernetes@v1.29.3/pkg/kubelet/images/puller.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 images
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/util/wait"
    25  	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
    26  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    27  )
    28  
    29  type pullResult struct {
    30  	imageRef     string
    31  	err          error
    32  	pullDuration time.Duration
    33  }
    34  
    35  type imagePuller interface {
    36  	pullImage(context.Context, kubecontainer.ImageSpec, []v1.Secret, chan<- pullResult, *runtimeapi.PodSandboxConfig)
    37  }
    38  
    39  var _, _ imagePuller = &parallelImagePuller{}, &serialImagePuller{}
    40  
    41  type parallelImagePuller struct {
    42  	imageService kubecontainer.ImageService
    43  	tokens       chan struct{}
    44  }
    45  
    46  func newParallelImagePuller(imageService kubecontainer.ImageService, maxParallelImagePulls *int32) imagePuller {
    47  	if maxParallelImagePulls == nil || *maxParallelImagePulls < 1 {
    48  		return &parallelImagePuller{imageService, nil}
    49  	}
    50  	return &parallelImagePuller{imageService, make(chan struct{}, *maxParallelImagePulls)}
    51  }
    52  
    53  func (pip *parallelImagePuller) pullImage(ctx context.Context, spec kubecontainer.ImageSpec, pullSecrets []v1.Secret, pullChan chan<- pullResult, podSandboxConfig *runtimeapi.PodSandboxConfig) {
    54  	go func() {
    55  		if pip.tokens != nil {
    56  			pip.tokens <- struct{}{}
    57  			defer func() { <-pip.tokens }()
    58  		}
    59  		startTime := time.Now()
    60  		imageRef, err := pip.imageService.PullImage(ctx, spec, pullSecrets, podSandboxConfig)
    61  		pullChan <- pullResult{
    62  			imageRef:     imageRef,
    63  			err:          err,
    64  			pullDuration: time.Since(startTime),
    65  		}
    66  	}()
    67  }
    68  
    69  // Maximum number of image pull requests than can be queued.
    70  const maxImagePullRequests = 10
    71  
    72  type serialImagePuller struct {
    73  	imageService kubecontainer.ImageService
    74  	pullRequests chan *imagePullRequest
    75  }
    76  
    77  func newSerialImagePuller(imageService kubecontainer.ImageService) imagePuller {
    78  	imagePuller := &serialImagePuller{imageService, make(chan *imagePullRequest, maxImagePullRequests)}
    79  	go wait.Until(imagePuller.processImagePullRequests, time.Second, wait.NeverStop)
    80  	return imagePuller
    81  }
    82  
    83  type imagePullRequest struct {
    84  	ctx              context.Context
    85  	spec             kubecontainer.ImageSpec
    86  	pullSecrets      []v1.Secret
    87  	pullChan         chan<- pullResult
    88  	podSandboxConfig *runtimeapi.PodSandboxConfig
    89  }
    90  
    91  func (sip *serialImagePuller) pullImage(ctx context.Context, spec kubecontainer.ImageSpec, pullSecrets []v1.Secret, pullChan chan<- pullResult, podSandboxConfig *runtimeapi.PodSandboxConfig) {
    92  	sip.pullRequests <- &imagePullRequest{
    93  		ctx:              ctx,
    94  		spec:             spec,
    95  		pullSecrets:      pullSecrets,
    96  		pullChan:         pullChan,
    97  		podSandboxConfig: podSandboxConfig,
    98  	}
    99  }
   100  
   101  func (sip *serialImagePuller) processImagePullRequests() {
   102  	for pullRequest := range sip.pullRequests {
   103  		startTime := time.Now()
   104  		imageRef, err := sip.imageService.PullImage(pullRequest.ctx, pullRequest.spec, pullRequest.pullSecrets, pullRequest.podSandboxConfig)
   105  		pullRequest.pullChan <- pullResult{
   106  			imageRef:     imageRef,
   107  			err:          err,
   108  			pullDuration: time.Since(startTime),
   109  		}
   110  	}
   111  }