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 }