@@ -178,41 +178,15 @@ func (m *imageManager) EnsureImageExists(ctx context.Context, objRef *v1.ObjectR
178
178
return "" , message , err
179
179
}
180
180
181
- if imageRef != "" && ! utilfeature .DefaultFeatureGate .Enabled (features .KubeletEnsureSecretPulledImages ) {
182
- msg := fmt .Sprintf ("Container image %q already present on machine" , requestedImage )
183
- m .logIt (objRef , v1 .EventTypeNormal , events .PulledImage , logPrefix , msg , klog .Info )
184
- return imageRef , msg , nil
185
- }
186
-
187
- repoToPull , _ , _ , err := parsers .ParseImageName (spec .Image )
188
- if err != nil {
189
- return "" , err .Error (), err
190
- }
181
+ // wrap the lookup in a function to ensure that we only look up credentials once and no earlier than needed
182
+ lookupPullCredentials := m .makeLookupPullCredentialsFunc (spec .Image , pod , pullSecrets , podSandboxConfig )
191
183
192
- // construct the dynamic keyring using the providers we have in the kubelet
193
- var podName , podNamespace , podUID string
194
- if utilfeature .DefaultFeatureGate .Enabled (features .KubeletServiceAccountTokenForCredentialProviders ) {
195
- sandboxMetadata := podSandboxConfig .GetMetadata ()
196
-
197
- podName = sandboxMetadata .Name
198
- podNamespace = sandboxMetadata .Namespace
199
- podUID = sandboxMetadata .Uid
200
- }
201
-
202
- externalCredentialProviderKeyring := credentialproviderplugin .NewExternalCredentialProviderDockerKeyring (
203
- podNamespace ,
204
- podName ,
205
- podUID ,
206
- pod .Spec .ServiceAccountName )
207
-
208
- keyring , err := credentialprovidersecrets .MakeDockerKeyring (pullSecrets , credentialprovider.UnionDockerKeyring {m .nodeKeyring , externalCredentialProviderKeyring })
209
- if err != nil {
210
- return "" , err .Error (), err
211
- }
212
-
213
- pullCredentials , _ := keyring .Lookup (repoToPull )
184
+ getPodCredentials := func () ([]kubeletconfiginternal.ImagePullSecret , * kubeletconfiginternal.ImagePullServiceAccount , error ) {
185
+ pullCredentials , err := lookupPullCredentials ()
186
+ if err != nil {
187
+ return nil , nil , err
188
+ }
214
189
215
- if imageRef != "" {
216
190
var imagePullSecrets []kubeletconfiginternal.ImagePullSecret
217
191
// we don't take the audience of the service account into account, so there can only
218
192
// be one imagePullServiceAccount per pod when we try to make a decision.
@@ -239,8 +213,18 @@ func (m *imageManager) EnsureImageExists(ctx context.Context, objRef *v1.ObjectR
239
213
}
240
214
}
241
215
242
- pullRequired := m .imagePullManager .MustAttemptImagePull (requestedImage , imageRef , imagePullSecrets , imagePullServiceAccount )
243
- if ! pullRequired {
216
+ return imagePullSecrets , imagePullServiceAccount , nil
217
+ }
218
+
219
+ if imageRef != "" {
220
+ if ! utilfeature .DefaultFeatureGate .Enabled (features .KubeletEnsureSecretPulledImages ) {
221
+ msg := fmt .Sprintf ("Container image %q already present on machine" , requestedImage )
222
+ m .logIt (objRef , v1 .EventTypeNormal , events .PulledImage , logPrefix , msg , klog .Info )
223
+ return imageRef , msg , nil
224
+ }
225
+ if pullRequired , err := m .imagePullManager .MustAttemptImagePull (requestedImage , imageRef , getPodCredentials ); err != nil {
226
+ return "" , err .Error (), err
227
+ } else if ! pullRequired {
244
228
msg := fmt .Sprintf ("Container image %q already present on machine and can be accessed by the pod" , requestedImage )
245
229
m .logIt (objRef , v1 .EventTypeNormal , events .PulledImage , logPrefix , msg , klog .Info )
246
230
return imageRef , msg , nil
@@ -254,9 +238,47 @@ func (m *imageManager) EnsureImageExists(ctx context.Context, objRef *v1.ObjectR
254
238
return "" , msg , err
255
239
}
256
240
241
+ pullCredentials , err := lookupPullCredentials ()
242
+ if err != nil {
243
+ return "" , err .Error (), err
244
+ }
245
+
257
246
return m .pullImage (ctx , logPrefix , objRef , pod .UID , requestedImage , spec , pullCredentials , podSandboxConfig )
258
247
}
259
248
249
+ func (m * imageManager ) makeLookupPullCredentialsFunc (image string , pod * v1.Pod , pullSecrets []v1.Secret , podSandboxConfig * runtimeapi.PodSandboxConfig ) func () ([]credentialprovider.TrackedAuthConfig , error ) {
250
+ return sync .OnceValues (func () ([]credentialprovider.TrackedAuthConfig , error ) {
251
+ repoToPull , _ , _ , err := parsers .ParseImageName (image )
252
+ if err != nil {
253
+ return nil , err
254
+ }
255
+
256
+ // construct the dynamic keyring using the providers we have in the kubelet
257
+ var podName , podNamespace , podUID string
258
+ if utilfeature .DefaultFeatureGate .Enabled (features .KubeletServiceAccountTokenForCredentialProviders ) {
259
+ sandboxMetadata := podSandboxConfig .GetMetadata ()
260
+
261
+ podName = sandboxMetadata .Name
262
+ podNamespace = sandboxMetadata .Namespace
263
+ podUID = sandboxMetadata .Uid
264
+ }
265
+
266
+ externalCredentialProviderKeyring := credentialproviderplugin .NewExternalCredentialProviderDockerKeyring (
267
+ podNamespace ,
268
+ podName ,
269
+ podUID ,
270
+ pod .Spec .ServiceAccountName )
271
+
272
+ keyring , err := credentialprovidersecrets .MakeDockerKeyring (pullSecrets , credentialprovider.UnionDockerKeyring {m .nodeKeyring , externalCredentialProviderKeyring })
273
+ if err != nil {
274
+ return nil , err
275
+ }
276
+
277
+ pullCredentials , _ := keyring .Lookup (repoToPull )
278
+ return pullCredentials , nil
279
+ })
280
+ }
281
+
260
282
func (m * imageManager ) pullImage (ctx context.Context , logPrefix string , objRef * v1.ObjectReference , podUID types.UID , image string , imgSpec kubecontainer.ImageSpec , pullCredentials []credentialprovider.TrackedAuthConfig , podSandboxConfig * runtimeapi.PodSandboxConfig ) (imageRef , message string , err error ) {
261
283
var pullSucceeded bool
262
284
var finalPullCredentials * credentialprovider.TrackedAuthConfig
0 commit comments