Conversation
Signed-off-by: Nishant Totla <[email protected]>
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
return reference.WithDigest(ref, dgst).String(), nil
daemon/image_pull.go
Outdated
There was a problem hiding this comment.
I'd suggest ignoring confirmedV2 here and attempting the Tags(ctx).Get() anyway. Worst case, it fails.
There was a problem hiding this comment.
Sounds fair. The check doesn't provide any particular advantages anyway.
daemon/image_pull.go
Outdated
There was a problem hiding this comment.
Return the Digest object rather than the stringified version.
468dbab to
8a5de2c
Compare
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
The if is not necessary - you can just do ref = reference.WithDefaultTag(ref) since WithDefaultTag is defined as follows:
// WithDefaultTag adds a default tag to a reference if it only has a repo name.
func WithDefaultTag(ref Named) Named {
if IsNameOnly(ref) {
ref, _ = WithTag(ref, DefaultTag)
}
return ref
}There was a problem hiding this comment.
You're right. I think I missed this after some refactoring.
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
namedTaggedRef, ok := ref.(reference.NamedTagged)
Return an error if ok is false (should not be possible currently, but the reference package could change in the future).
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
This should probably be a Debugf, and ideally should provide more context about what was pinned. I'd suggest creating a logger at the top of this function with logrus.WithFields. Then if you use that logger for the log messages, they can have the service name, image reference, and so on filled in.
There was a problem hiding this comment.
I moved these log messages outside this function, which now only returns an error, and the caller decides what to do with it.
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
Move this above the if encodedAuth != "" { so cntr can be reused there.
ef09483 to
288fe63
Compare
c543b7b to
869ed54
Compare
|
@aaronlehmann I've addressed all your comments. Please let me know if this looks acceptable. The only thing I haven't quite decided is what fields to add to Also cc @tonistiigi. |
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
This would log an error message if the user already provided a digest. How about making imageWithDigestString return image, nil if the image already has a digest specified, and then this code can only log "pinning image..." if digestImage != newCntr.Image?
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
Don't make the error path in the main path. Get in the habit of making an early return.
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
Why wouldn't we return the canonical reference if it is already canonical?
if canonical, ok := ref.(reference.Canonical); ok {
return canonical, nil
}
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
encodedAuth should really be cross-cutting. Perhaps, store in the backed or preconfigure an object with the auth before calling this method.
There was a problem hiding this comment.
@stevvooe if I understand correctly, passing the types.AuthConfig struct to this function would be acceptable?
There was a problem hiding this comment.
That is probably a first step. It is hard to tell, since it is not actually being used. I have no clue why we would bury an unencoded value so deeply in the call stack. The auth should probably be decoded as soon as the request is received. Then, I would put it in the context and access as needed, without passing it down the entire call chain.
daemon/image_pull.go
Outdated
There was a problem hiding this comment.
Rather than add yet another method to daemon, why not export access to the configured repository? As it is, this method is very narrow and not very flexible. Ideally, we give it an image reference and get back fully configured repository.
There was a problem hiding this comment.
Will make this function return a fully configured repository to expand its usability.
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
if err != nil {
log warning
} else if digestImage != ctnr.Image {
log debug(pinning)
ctnr.Image = digestImage
}
daemon/cluster/cluster.go
Outdated
There was a problem hiding this comment.
is this expected not to error out?
There was a problem hiding this comment.
Any operations related to pinning by digest aren't supposed to error out right now, because some people use local images in dev, and this would break that workflow.
daemon/image_pull.go
Outdated
There was a problem hiding this comment.
This should return lastError instead of nil, it is possible that the last endpoint returned an error and caused repository to be nil.
Signed-off-by: Nishant Totla <[email protected]>
fde412c to
764a9ed
Compare
|
One thing I just thought of is that we should avoid re-pulling the image when the task starts if the image is pinned by digest and it already exists locally. This will make task startup faster and reduce unnecessary registry traffic. This should be checked in the I'd suggest doing this in a separate PR before the release. |
|
Tested and this works for me. LGTM Thanks for that list of action items. It looks good to me. I would add one more - add an integration test that covers pinning by digest. |
|
LGTM |
1 similar comment
|
LGTM |
|
@thaJeztah this needs a |
- What I did
When a Docker Swarm mode service is created using the image and tag, the agents pull image with the specified tag. This creates an issue for non-static tags like
latest, which keep updating. This might cause multiple versions of the image running for the same service. The solution to this problem is to pin images by digest.For example, on
docker service create alpine:latest top, the manifest for thealpine:latestimage is retrieved, and the digest is added to the image description before passing on the spec to the SwarmKit manager. In this case,alpine:latestis changed toalpine:latest@sha256:1354db23ff5478120c980eca1611a51c9f2b88b61f24283ee8200bf9a54f2e5cthat specifies an image precisely. If at a future time, the image underalpine:latestwere to have a different digest, this would be detected at the nextservice update, and all images would be pinned to the new digest.Related issues: #24066, #27508, moby/swarmkit#1334
- How I did it
The change is fairly simple. A new daemon function
ResolveTagToDigestis used to retrieve a digest for areference.NamedTaggedobject, by making a request to the registry. This function is used bydocker service createanddocker service updateto resolve image to digest, if the image used to create the service didn't already have it.The service spec is modified before passing to the SwarmKit manager to always contain a digest string, thereby ensuring that a service image is always precisely specified. On image update, a digest is retrieved again, and if different from the existing one, will result in a service update.
One thing that remains to be done is to enable pinning by digest for private images (this is a minor addition which I will shortly finish) by passing
AuthConfigtoResolveTagToDigest.- How to verify it
Try the following commands:
This should show the image as
alpine:latest@sha256:1354db23ff5478120c980eca1611a51c9f2b88b61f24283ee8200bf9a54f2e5cThis will show the image updated to
alpine:edge@sha256:cd9c03c2d382fcf00c31dc1635445163ec185dfffb51242d9e097892b3b0d5b4NOTE: It is by choice that the operation won't fail if the digest retrieval fails for some reason. It will only print a warning and move on. This is to make sure that the use case where a locally built image might be used to create a service still works.
- Description for the changelog
Pin images by digest for docker service create and update
- A picture of a cute animal (not mandatory but encouraged)
This is Mutsu the kitten. For more of Mutsu, you can check here