k8s.io/kubernetes@v1.29.3/pkg/kubelet/kuberuntime/kuberuntime_image.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 kuberuntime
    18  
    19  import (
    20  	"context"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    24  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    25  	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
    26  	"k8s.io/klog/v2"
    27  	credentialprovidersecrets "k8s.io/kubernetes/pkg/credentialprovider/secrets"
    28  	"k8s.io/kubernetes/pkg/features"
    29  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    30  	"k8s.io/kubernetes/pkg/util/parsers"
    31  )
    32  
    33  // PullImage pulls an image from the network to local storage using the supplied
    34  // secrets if necessary.
    35  func (m *kubeGenericRuntimeManager) PullImage(ctx context.Context, image kubecontainer.ImageSpec, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {
    36  	img := image.Image
    37  	repoToPull, _, _, err := parsers.ParseImageName(img)
    38  	if err != nil {
    39  		return "", err
    40  	}
    41  
    42  	keyring, err := credentialprovidersecrets.MakeDockerKeyring(pullSecrets, m.keyring)
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  
    47  	imgSpec := toRuntimeAPIImageSpec(image)
    48  
    49  	creds, withCredentials := keyring.Lookup(repoToPull)
    50  	if !withCredentials {
    51  		klog.V(3).InfoS("Pulling image without credentials", "image", img)
    52  
    53  		imageRef, err := m.imageService.PullImage(ctx, imgSpec, nil, podSandboxConfig)
    54  		if err != nil {
    55  			klog.ErrorS(err, "Failed to pull image", "image", img)
    56  			return "", err
    57  		}
    58  
    59  		return imageRef, nil
    60  	}
    61  
    62  	var pullErrs []error
    63  	for _, currentCreds := range creds {
    64  		auth := &runtimeapi.AuthConfig{
    65  			Username:      currentCreds.Username,
    66  			Password:      currentCreds.Password,
    67  			Auth:          currentCreds.Auth,
    68  			ServerAddress: currentCreds.ServerAddress,
    69  			IdentityToken: currentCreds.IdentityToken,
    70  			RegistryToken: currentCreds.RegistryToken,
    71  		}
    72  
    73  		imageRef, err := m.imageService.PullImage(ctx, imgSpec, auth, podSandboxConfig)
    74  		// If there was no error, return success
    75  		if err == nil {
    76  			return imageRef, nil
    77  		}
    78  
    79  		pullErrs = append(pullErrs, err)
    80  	}
    81  
    82  	return "", utilerrors.NewAggregate(pullErrs)
    83  }
    84  
    85  // GetImageRef gets the ID of the image which has already been in
    86  // the local storage. It returns ("", nil) if the image isn't in the local storage.
    87  func (m *kubeGenericRuntimeManager) GetImageRef(ctx context.Context, image kubecontainer.ImageSpec) (string, error) {
    88  	resp, err := m.imageService.ImageStatus(ctx, toRuntimeAPIImageSpec(image), false)
    89  	if err != nil {
    90  		klog.ErrorS(err, "Failed to get image status", "image", image.Image)
    91  		return "", err
    92  	}
    93  	if resp.Image == nil {
    94  		return "", nil
    95  	}
    96  	return resp.Image.Id, nil
    97  }
    98  
    99  // ListImages gets all images currently on the machine.
   100  func (m *kubeGenericRuntimeManager) ListImages(ctx context.Context) ([]kubecontainer.Image, error) {
   101  	var images []kubecontainer.Image
   102  
   103  	allImages, err := m.imageService.ListImages(ctx, nil)
   104  	if err != nil {
   105  		klog.ErrorS(err, "Failed to list images")
   106  		return nil, err
   107  	}
   108  
   109  	for _, img := range allImages {
   110  		// Container runtimes may choose not to implement changes needed for KEP 4216. If
   111  		// the changes are not implemented by a container runtime, the exisiting behavior
   112  		// of not populating the runtimeHandler CRI field in ImageSpec struct is preserved.
   113  		// Therefore, when RuntimeClassInImageCriAPI feature gate is set, check to see if this
   114  		// field is empty and log a warning message.
   115  		if utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClassInImageCriAPI) {
   116  			if img.Spec == nil || (img.Spec != nil && img.Spec.RuntimeHandler == "") {
   117  				klog.V(2).InfoS("WARNING: RuntimeHandler is empty", "ImageID", img.Id)
   118  			}
   119  		}
   120  
   121  		images = append(images, kubecontainer.Image{
   122  			ID:          img.Id,
   123  			Size:        int64(img.Size_),
   124  			RepoTags:    img.RepoTags,
   125  			RepoDigests: img.RepoDigests,
   126  			Spec:        toKubeContainerImageSpec(img),
   127  			Pinned:      img.Pinned,
   128  		})
   129  	}
   130  
   131  	return images, nil
   132  }
   133  
   134  // RemoveImage removes the specified image.
   135  func (m *kubeGenericRuntimeManager) RemoveImage(ctx context.Context, image kubecontainer.ImageSpec) error {
   136  	err := m.imageService.RemoveImage(ctx, &runtimeapi.ImageSpec{Image: image.Image})
   137  	if err != nil {
   138  		klog.ErrorS(err, "Failed to remove image", "image", image.Image)
   139  		return err
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  // ImageStats returns the statistics of the image.
   146  // Notice that current logic doesn't really work for images which share layers (e.g. docker image),
   147  // this is a known issue, and we'll address this by getting imagefs stats directly from CRI.
   148  // TODO: Get imagefs stats directly from CRI.
   149  func (m *kubeGenericRuntimeManager) ImageStats(ctx context.Context) (*kubecontainer.ImageStats, error) {
   150  	allImages, err := m.imageService.ListImages(ctx, nil)
   151  	if err != nil {
   152  		klog.ErrorS(err, "Failed to list images")
   153  		return nil, err
   154  	}
   155  	stats := &kubecontainer.ImageStats{}
   156  	for _, img := range allImages {
   157  		stats.TotalStorageBytes += img.Size_
   158  	}
   159  	return stats, nil
   160  }
   161  
   162  func (m *kubeGenericRuntimeManager) ImageFsInfo(ctx context.Context) (*runtimeapi.ImageFsInfoResponse, error) {
   163  	allImages, err := m.imageService.ImageFsInfo(ctx)
   164  	if err != nil {
   165  		klog.ErrorS(err, "Failed to get image filesystem")
   166  		return nil, err
   167  	}
   168  	return allImages, nil
   169  }