Skip to content

Moving docker service digest pinning to client side#32388

Merged
tiborvass merged 2 commits intomoby:masterfrom
nishanttotla:pin-by-digest-on-client-alternative
May 16, 2017
Merged

Moving docker service digest pinning to client side#32388
tiborvass merged 2 commits intomoby:masterfrom
nishanttotla:pin-by-digest-on-client-alternative

Conversation

@nishanttotla
Copy link
Contributor

@nishanttotla nishanttotla commented Apr 5, 2017

This PR is an alternative proposal to #32384, based on discussions with @aluzzardi @dhiltgen @alexmavr.

The heavy lifting in this case happens in the client package, which is easier to use for third-party clients, and they get the benefit of client-side digest pinning without having to do it themselves.

cc @aaronlehmann

- What I did
Digest pinning was introduced for Docker services in #28173, and it was performed on the daemon. After #32061, I moved digest pinning to the client, simplifying it.

- How I did it
The client makes a call to /images/image_name/manifest to retrieve manifest information, which contains the image digest.

- How to verify it
docker service create --name test alpine sleep 1000 then docker service inspect test should contain an image with the digest.

- Description for the changelog

Docker service image pin by digest moved to client side.

- WIP

- A picture of a cute animal (not mandatory but encouraged)
goshi

This is Gosha, the friendliest cat in Berkeley.

Copy link

@alexmavr alexmavr Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the Image is already a manifest? It looks like we're going to throw a warning

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the image already contains a digest? Then the digest will be used to retrieve the manifest, and platform information added (this is not part of this PR, and will come later in a separate PR). Without the platform information stuff, we could just skip this call altogether.

@aaronlehmann
Copy link

I'm okay with this approach but I think we should add a flag in ServiceCreateOptions to let API users opt in or opt out. Otherwise it would be impossible to use the client to create a service that isn't pinned to a digest.

@nishanttotla
Copy link
Contributor Author

@aaronlehmann I agree, I'll add that. Are there any cons to this approach, apart from having to move digest pinning away from content-trust?

@aaronlehmann
Copy link

I think it's problematic for the "service update" case. We should only be messing with the image field or the platform info if the user actually specified --image on the command line - it shouldn't be a side effect of an unrelated change like scaling the service. In the CLI it's easy to gate this stuff with an if flags.Changed("image"), but if it's in the client and it's something we have to explicitly enable or disable, it seems a bit more awkward. Not a dealbreaker but I think it's definitely awkward for the update case if we do it this way.

What if we moved resolveServiceImageDigest from the other PR into client?

@nishanttotla
Copy link
Contributor Author

@aaronlehmann I'll update ServiceUpdateOptions to include a field indicating if flags.Changed("image").

When you say moving resolveServiceImageDigest to the client package, do you also want to move content trust here? It doesn't look difficult to do, and also alleviates some of my concerns with this PR separating digest pinning and content trust into separate places.

@aaronlehmann
Copy link

When you say moving resolveServiceImageDigest to the client package, do you also want to move content trust here? It doesn't look difficult to do, and also alleviates some of my concerns with this PR separating digest pinning and content trust into separate places.

I'm not sure. It sounds like a good idea if it's possible. But I seem to remember that content trust involves a lot of code that lives in cli.

@nishanttotla
Copy link
Contributor Author

@aaronlehmann let me take a look. If it's easy to refactor, I'll include it in this PR.

@nishanttotla
Copy link
Contributor Author

Update: Trust code is definitely entrenched in the CLI, and while it seems "refactorable", I don't think it should be a part of this PR because it is associated with content trust for running containers as well.

@nishanttotla nishanttotla force-pushed the pin-by-digest-on-client-alternative branch 3 times, most recently from f0467f7 to 0726fea Compare April 6, 2017 19:20
@nishanttotla
Copy link
Contributor Author

@aaronlehmann: updated this PR. Added a field called UpdateImage to ServiceCreateOptions that gets set when the --image flag is provided. In the future, it can also be easily used to disable digest pinning from the client.

I also updated resolveServiceImageDigest to resolveServiceImageDigestContentTrust to indicate that it only resolves digest by content trust. In the future, we should move this function to the client package.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's name this something like QueryRegistry, since I guess it will be extended to things other than pinning by digest in the future (platform info...).

I think we should support the same flag for ServiceCreate, so that digest pinning is not mandatory for all client users.

Let's not mention the --image flag (except possibly as an example), because the client is independent of the Docker CLI.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must not overwrite the Image field here if it already contains a digest (for example, if digest pinning was already done through content trust).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must not overwrite the Image field here if it already contains a digest (for example, if digest pinning was already done through content trust).

@nishanttotla nishanttotla force-pushed the pin-by-digest-on-client-alternative branch 2 times, most recently from 286eb0e to 514baad Compare April 6, 2017 23:30
@nishanttotla
Copy link
Contributor Author

@aaronlehmann: addressed your comments.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right. We should be replacing the Image field if the image reference doesn't have a digest, not if it doesn't parse.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reasoning for this was to not update the image if it parses to a legitimate canonical reference AND a manifest is retrieved. Is that not what this is doing? I wanted to reuse something from the distribution/reference package. Do you recommend something else?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does it check that the reference is canonical?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func ParseNamed(s string) (Named, error) {
	named, err := ParseNormalizedNamed(s)
	if err != nil {
		return nil, err
	}
	if named.String() != s {
		return nil, ErrNameNotCanonical
	}
	return named, nil
}

This check I believed was doing that, but perhaps I'm getting it wrong.

f named.String() != s {
		return nil, ErrNameNotCanonical
	}

Adding a type check for reference.Canonical should fix that?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That "canonical" is something else :(

Adding a type check for reference.Canonical should fix that?

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, let me add that. I wasn't going by the word "canonical" as much as the string check, but it's embarrassing now because that doesn't make any sense. Fixing it now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@nishanttotla nishanttotla force-pushed the pin-by-digest-on-client-alternative branch from 514baad to 39a9b94 Compare April 7, 2017 01:08
@dnephin dnephin mentioned this pull request Apr 7, 2017
6 tasks
@vieux vieux added this to the 17.06 milestone Apr 7, 2017
@nishanttotla nishanttotla changed the title [WIP][Alternative] Moving docker service digest pinning to client side [WIP] Moving docker service digest pinning to client side Apr 11, 2017
@clnperez
Copy link
Contributor

Since @dnephin mentioned that this my conflict with my PR (/pull/27455), @nishanttotla can you clarify whether the imageManifest func you're adding pulls from the registry or expects the image to be pre-pulled?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be var distErr error (but it doesn't matter).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a good reason to continue supporting DOCKER_SERVICE_PREFER_OFFLINE_IMAGE? This was for the integration tests, but if the integration tests use the latest API version, they shouldn't hit this code path anyway.

That said, it may take some work to get things right with the integration tests after removing this. It may be best to remove it in a followup. Speaking of which, how will we prevent CLI-oriented integration tests from trying to resolve digests for local images on Docker Hub? Should we add a CLI option to prevent digest pinning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems correct, we shouldn't have to keep DOCKER_SERVICE_PREFER_OFFLINE_IMAGE, but it does absolutely no harm right now, and isn't user facing, so we should just wait on removing it. I'll add a comment indicating this.

If the CLI-oriented tests will purely run CLI commands, then we will have to add a flag, there is no other way. Given that we know of scenarios where disabling is required, we should add the flag.

@aaronlehmann
Copy link

Mostly LGTM, but a little concerned that moving digest pinning to the client side will break the DOCKER_SERVICE_PREFER_OFFLINE_IMAGE workaround, and cause integration tests that use docker service create or docker service update --image in the CLI to interact with the hub when they really should not. I think we either need to add a flag to disable digest pinning in the CLI, or rewrite the applicable integration tests to avoid the CLI.

@nishanttotla nishanttotla force-pushed the pin-by-digest-on-client-alternative branch from b2368aa to 6a43422 Compare May 13, 2017 04:38
@nishanttotla
Copy link
Contributor Author

@aluzzardi what do you think about adding a flag? It shouldn't be hard to do, given that this PR already has an API-level option to disable the registry lookup.

@aluzzardi
Copy link
Member

@nishanttotla @aaronlehmann A flag sounds great, I think it was one of the goals of moving resolution client side.

May I suggest --no-resolve-image or something like that?

@nishanttotla
Copy link
Contributor Author

@aluzzardi @aaronlehmann I'll open a follow-up PR for that, since most changes will be in docker/cli, and we might need some time to agree on the flag name and behavior.

@aaronlehmann
Copy link

That sounds okay. Hopefully the circular dependency between moby and cli doesn't put us in a state where integration tests are trying to perform digest pinning (which makes them flaky). Ideally the commit that updates moby to point to a revision of cli that does the digest pinning will also update the integration tests to use the new flag that disables it.

@nishanttotla
Copy link
Contributor Author

I'll add the flag to the same PR (docker/cli#30) that enables the QueryRegistry option in the CLI.

@nishanttotla nishanttotla force-pushed the pin-by-digest-on-client-alternative branch from 6a43422 to c0afd9c Compare May 15, 2017 23:43
@aaronlehmann
Copy link

LGTM

// image name that could not be pinned by digest. The formatting
// is hardcoded, but could me made smarter in the future
func digestWarning(image string) string {
return fmt.Sprintf("image %s could not be accessed on a registry to record\nits digest. Each node will access %s independently,\npossibly leading to different nodes running different\nversions of the image.\n", image, image)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the \n in the middle like that is kinda unusual

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tiborvass this is to add line breaks, since the text is big. This is how it is also in the daemon right now.

// contacting a registry. A registry may be contacted to retrieve
// the image digest and manifest, which in turn can be used to update
// platform or other information about the service.
QueryRegistry bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nishanttotla I'm wondering if the default shouldn't be the current behavior. SkipRegistryQuery ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tiborvass the corresponding CLI PR is docker/cli#30.

The idea is that QueryRegistry should be set on all service create commands unless the user explicitly provides a flag to prevent it, and for all service update commands that update the image, using the --image flag (also unless the user explicitly asks to not do it with the flag).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tiborvass: The current behavior is that the client does not perform this query.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aaronlehmann my bad i thought this was server side.

@tiborvass
Copy link
Contributor

LGTM

@tiborvass tiborvass merged commit d6f4fe9 into moby:master May 16, 2017
@nishanttotla nishanttotla deleted the pin-by-digest-on-client-alternative branch May 16, 2017 22:24
@nishanttotla
Copy link
Contributor Author

Adding link back to #31348

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.