-
Notifications
You must be signed in to change notification settings - Fork 18.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove containerd "platform" dependency from client #42623
Remove containerd "platform" dependency from client #42623
Conversation
@cpuguy83 @dims @AkihiroSuda PTAL |
LGTM @thaJeztah thanks! |
Added the cherry-pick label; I tried to keep this diff small/localised so that we are able to cherry-pick (helps kubernetes / cAdvisor) |
// instead of "unknown" if no OS is present: https://github.com/containerd/containerd/blob/v1.5.2/platforms/platforms.go#L243-L263 | ||
func formatPlatform(platform *specs.Platform) string { | ||
if platform == nil || platform.OS == "" { | ||
return "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me call out here that containerd's format would return "unknown"
in this case. As far as I can see, we have no use for the "unknown"
value, and would treat it equivalent to ""
/ not set, so I went for "don't set the parameter if we don't have anything useful". but perhaps I overlooked a specific scenario 👀 👀 👀 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, buildkit supports just setting arch... weird that we'd return empty for empty OS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked up the parsing on the daemon side, and looks indeed that that should be supported; if only arch
is specified, the parsing on the daemon side should handle that;
moby/vendor/github.com/containerd/containerd/platforms/platforms.go
Lines 182 to 206 in ada51d6
case 1: | |
// in this case, we will test that the value might be an OS, then look | |
// it up. If it is not known, we'll treat it as an architecture. Since | |
// we have very little information about the platform here, we are | |
// going to be a little more strict if we don't know about the argument | |
// value. | |
p.OS = normalizeOS(parts[0]) | |
if isKnownOS(p.OS) { | |
// picks a default architecture | |
p.Architecture = runtime.GOARCH | |
if p.Architecture == "arm" && cpuVariant() != "v7" { | |
p.Variant = cpuVariant() | |
} | |
return p, nil | |
} | |
p.Architecture, p.Variant = normalizeArch(parts[0], "") | |
if p.Architecture == "arm" && p.Variant == "v7" { | |
p.Variant = "" | |
} | |
if isKnownArch(p.Architecture) { | |
p.OS = runtime.GOOS | |
return p, nil | |
} |
Why are we duplicating this code? Same for #42464 . If for example windows os-version starts to get encoded in the string value(there is an issue for that somewhere) there are two incompatible implementations. I don't see an issue with depending on the specs repo. |
// | ||
// Similar to containerd's platforms.Format(), but returns an empty string | ||
// instead of "unknown" if no OS is present: https://github.com/containerd/containerd/blob/v1.5.2/platforms/platforms.go#L243-L263 | ||
func formatPlatform(platform *specs.Platform) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we really want path.Join(platform.OS, platform.Arch....)
This will handle empty values as desired, even for empty values.
https://play.golang.org/p/ztICsyudOrB
Not sure if you want to validate that is always arch is set if variant is also set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, nice! TIL path.Join
skips the empty values (I assumed it would keep those in). Yes, I like that.
Not sure if you want to validate that is always arch is set if variant is also set.
Yeah, perhaps stop at the first empty value (in which case path.Join
would not be needed 🤔). We could keep it "simple" (for now), and just let the daemon handle this; wdyt?
I was writing down notes on serializing / deserialising and normalising of oci.Platform (to start a discussion on the OCI spec), because currently it looks like there's no standard approach anywhere.
So add to the "silliness"; I was looking at the CLI code YesterdayI: https://github.com/docker/cli/blob/v20.10.7/cli/command/container/create.go#L244-L249
if opts.platform != "" && versions.GreaterThanOrEqualTo(dockerCli.Client().ClientVersion(), "1.41") {
p, err := platforms.Parse(opts.platform)
if err != nil {
return nil, errors.Wrap(err, "error parsing specified platform")
}
platform = &p
So, we:
- pass a string representation of platform (through the
--platform
flag) - parse it on the CLI to convert it to an
oci.Platform{}
- pass it to the client as argument
- convert it to a string
- send it over the API as a string
- parse the string and convert it to an
oci.Platform{}
- pass it to the backend as argument
Looking at that, I think we should consider to either have the client (and cli) to not bother with oci.Platform{}
at all (pass a string, and let the daemon deal with it), or make the API accept a oci.Platform{}
(or equivalent) in the request.
db3e1e0
to
33a0513
Compare
@cpuguy83 updated to use |
@cpuguy83 @tianon @tonistiigi ptal |
This field was added in 7a9cb29, but appears to be unused, so removing it. Signed-off-by: Sebastiaan van Stijn <[email protected]>
33a0513
to
9a27002
Compare
Signed-off-by: Sebastiaan van Stijn <[email protected]>
9a27002
to
5f0703c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
LGTM ... is that an unrelated flake in the failing test?
|
Yes, should be unrelated (but looks like it's become more flaky); #42698 |
Generally seems OK to me, but I am concerned that this particular code path probably doesn't have very much coverage in any of our tests and this formatting is slightly different from what containerd does (so I guess there's some regression potential here?). 😕 Not sure there's a good solution to this, though. |
So, looking at the differences again, I think the only difference is that containerd returns The "unknown" case would produce an error if sent to the daemon ( package main
import (
"fmt"
"github.com/containerd/containerd/platforms"
)
func main() {
p, err := platforms.Parse("unknown")
if err != nil {
fmt.Println(err)
}
fmt.Println(platforms.Format(p))
p, err = platforms.Parse("armhf")
if err != nil {
fmt.Println(err)
}
fmt.Println(platforms.Format(p))
} go run main.go
"unknown": unknown operating system or architecture: invalid argument
unknown
linux/arm However (see #42623 (comment)), in the This brings of course question: "should it?" (that's what my comment above was about: #42623 (comment)). Because currently, omitting the OS will result in the OS of the cli to be used as default 😂; $ docker run --rm --platform=arm64 hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
109db8fad215: Pull complete
Digest: sha256:df5f5184104426b65967e016ff2ac0bfcd44ad7899ca3bbcf8e44e4461491a9e
Status: Downloaded newer image for hello-world:latest
docker: Error response from daemon: image with reference hello-world was found but does not match the specified platform: wanted darwin/arm64, actual: linux/arm64/v8.
See 'docker run --help'. Something to look at in a follow-up; I think we should consider passing what's provided by the user as-is. The daemon (API) will produce an error if it's invalid, and the daemon can (if needed) fill in defaults. |
Fair enough; SGTM
|
YESSS!!! thanks @thaJeztah |
Note: once / if #42464 is merged/accepted, we should consider replacing
github.com/opencontainers/image-spec/specs-go/v1.Platform
with our ownImagePlatform
, to remove the OCI spec from the API (if possible). If we do so, we can also remove theformatPlatform
function here (as it would be provided byImagePlatform.String()
This removes some of the containerd dependencies from the client:
This field was added in 7a9cb29, but appears to be unused, so removing it.
After this, there's no direct dependency on containerd, but the
errdefs
package still depends on containerd's errdefs. package. I'll have a look if we can refactor so that that doesn't end up in the client package.