close
Skip to content

daemon: allow setting OCI annotations on containers - #45025

Merged
cpuguy83 merged 2 commits into
moby:masterfrom
corhere:oci-annotation-passthru
Feb 24, 2023
Merged

daemon: allow setting OCI annotations on containers#45025
cpuguy83 merged 2 commits into
moby:masterfrom
corhere:oci-annotation-passthru

Conversation

@corhere

@corhere corhere commented Feb 17, 2023

Copy link
Copy Markdown
Contributor

- What I did

Allow API clients to set and retrieve OCI annotations on a container.

- How I did it

Added a field to HostConfig and plumbed it into the OCI spec generation code.

- How to verify it
Create a container with annotations and start it. Inspect the running container using ctr and verify that the annotations are listed in the container spec.

A new integration test verifies that annotations can be round-tripped through the Engine API.

- Description for the changelog

  • Annotations—arbitrary non-identifying metadata—can now be attached to containers on creation which will be passed to the runtime when the container is started.

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

@thaJeztah

Copy link
Copy Markdown
Member

Will these labels be committed in the image on docker commit ? (also see #42037) And does this mean that an image containing these labels will set them at runtime on the container?

@corhere

corhere commented Feb 17, 2023

Copy link
Copy Markdown
Contributor Author

Will these labels be committed in the image on docker commit ? (also see #42037)

Yes, until the aforementioned PR is merged.

And does this mean that an image containing these labels will set them at runtime on the container?

Yes. This could arguably be a feature.

@thaJeztah

Copy link
Copy Markdown
Member

Yes. This could arguably be a feature.

We should probably look closely what's desirable in that case. I recall there was some prior discussion on passing through labels as annotations. I must admit I'm not fully aware how they're used / what they're able to control, but ISTR there were some concerns that had to be looked into (e.g. a malicious image could set a label and do other things than expected).

I guess to some extent that's not "our" issue (as we don't consume those annotations?).

It does somewhat bring back the issue though that we don't have a concept of "runtime" labels and "non-runtime" (image labels are runtime labels in our case, or at least inherited directly, and in case of "commit", baked into the image).

Probably also need to be looked at what the expectations are for docker container update, as there's been quite some requests on being able to update labels; prior discussions stranded on that one, but if that would be implemented, that may have an effect on the feature in this PR.

@AkihiroSuda AkihiroSuda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And does this mean that an image containing these labels will set them at runtime on the container?

Yes. This could arguably be a feature.

This looks like an attack vector.

Specifying annotations should require a new API/CLI like
docker run --annotation=com.example.foo=bar.
(similar to podman run --annotation)

@corhere
corhere marked this pull request as draft February 17, 2023 13:50
@corhere
corhere force-pushed the oci-annotation-passthru branch from 9141b45 to 45a23c1 Compare February 17, 2023 20:11
@corhere corhere changed the title daemon: allow setting OCI annotations using container labels daemon: allow setting OCI annotations on containers Feb 17, 2023
@corhere
corhere force-pushed the oci-annotation-passthru branch from 45a23c1 to a2aa9c3 Compare February 17, 2023 20:30
@corhere
corhere marked this pull request as ready for review February 17, 2023 20:30

@cpuguy83 cpuguy83 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

SGTM

But need to update the API history doc and openapi yaml.

Signed-off-by: Cory Snider <csnider@mirantis.com>
@corhere
corhere force-pushed the oci-annotation-passthru branch from a2aa9c3 to 8656719 Compare February 21, 2023 18:34
Comment on lines +566 to +569
if hostConfig != nil && versions.LessThan(version, "1.43") {
// Ignore OCIAnnotations because it was added in API v1.43.
hostConfig.OCIAnnotations = nil
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm following past precedent by ignoring the field on create for older API versions but unconditionally including it in the /containers/{}/json response for all API versions.

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

("requesting changes" just to have a quick check per my comment - changes otherwise look good to me)

Comment thread api/types/container/hostconfig.go Outdated
VolumeDriver string // Name of the volume driver used to mount volumes
VolumesFrom []string // List of volumes to take from other container
ConsoleSize [2]uint // Initial console size (height,width)
OCIAnnotations map[string]string `json:",omitempty"` // Annotations to pass along to OCI runtime

@thaJeztah thaJeztah Feb 22, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Before we merge; quick check on the naming. Wondering if OCI prefix is needed in our API here. I get where we're coming from; mostly thinking along the lines of "(almost) every option we have in our API leads to <something> OCI spec.

So wondering if we should keep the abstraction - call it Annotations, and keep the fact that that (currently) gets passed on to the OCI to the description only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm coming around to dropping the OCI prefix and adopting essentially the same semantics as Kubernetes Annotations. And by that I mean documenting that Engine API clients can also leverage annotations to attach and consume metadata on containers for their own purposes. Perhaps we should also follow their lead and enforce a particular syntax for annotation keys so that the namespace of an annotation is unambiguous. We could always loosen validation later but can't make it more restrictive.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's discuss / brainstorm in the call later Today (I also need to get my head around all of that). Quick comment;

  • Yes, I think Annotations could be useful for "our side" as well
  • I like namespaces / prefixes as they can definitely help prevent ambiguity (I think I may actually have been the one originally getting them into the "labels" definition 🤔 )
  • ^^^ w.r.t. namespaces: I always keep in the back of my mind that API !== UX; namespaces are awkward to use, but are (in most cases) not meant for humans. So if we decide to use namespaces, we can still make the UX "different" (docker run --foo=bar doing docker run --annotation=awkwardly-long-namespace.option=bar behind the scenes)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What I like about how K8s goes about namespacing annotations is that it makes namespace prefixes optional and reserves the no-namespace "namespace" for users.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yup, that was part of my original suggestion for labels; no-namespace is for users; don't use them for automation as they can easily conflict. For automation / tools, always use a prefix

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For those interested; here's the PR with all the fun (well, there's been multiple before that, but that's the one that made it, and that one is already 200+ comments 🤣)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Decisions from today's maintainer call:

  • Drop the OCI prefix from the field name
  • Any annotation which is valid per the OCI Runtime spec is permitted
    • Keys can be any JSON string except for the empty string
    • Values can be any JSON string, including the empty string
    • Keys and values can be arbitrarily long

Allow clients to set annotations on a container which will applied to
the container's OCI spec.

Signed-off-by: Cory Snider <csnider@mirantis.com>
@corhere
corhere force-pushed the oci-annotation-passthru branch from 8656719 to 0ffaa6c Compare February 23, 2023 23:59

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks!

Comment thread daemon/container.go
}
for k := range hostConfig.Annotations {
if k == "" {
return errors.Errorf("invalid Annotations: the empty string is not permitted as an annotation key")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I had a look if we should be using an errdefs.InvalidParameter() here (and noticed other errors didn't), but it looks like we wrap any errors returned here on the call sites, such as

moby/daemon/create.go

Lines 65 to 68 in 2f0e308

warnings, err := daemon.verifyContainerSettings(opts.params.HostConfig, opts.params.Config, false)
if err != nil {
return containertypes.CreateResponse{Warnings: warnings}, errdefs.InvalidParameter(err)
}

So in either case; it's good (currently) to not use an errdefs, but we could (should?) look at these at some points to assign error-types in these locations.

@thaJeztah thaJeztah added this to the v-next milestone Feb 24, 2023
@thaJeztah

Copy link
Copy Markdown
Member

@cpuguy83 LGTY? (I see there's a "change requested" from you, and didn't want to dismiss it)

Screenshot 2023-02-24 at 14 56 38

@AkihiroSuda

Copy link
Copy Markdown
Member

@corhere Do you have a PR for the CLI?

@corhere

corhere commented Mar 24, 2023

Copy link
Copy Markdown
Contributor Author

@AkihiroSuda no, I am not working on a CLI PR as my motivation is unblocking support for alternative runtimes in cri-dockerd.

@AkihiroSuda

Copy link
Copy Markdown
Member

Opened a PR for the CLI:

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.

6 participants