diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 31a73078ad..ddf666a390 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -122,7 +122,7 @@ RUN eval "$(gimme "${GO_VERSION}")" \ # stage for building containerd FROM go-build AS build-containerd ARG TARGETARCH GO_VERSION -ARG CONTAINERD_VERSION="v1.7.24" +ARG CONTAINERD_VERSION="v2.0.1" ARG CONTAINERD_CLONE_URL="https://github.com/containerd/containerd" # we don't build with optional snapshotters, we never select any of these # they're not ideal inside kind anyhow, and we save some disk space diff --git a/pkg/build/nodeimage/imageimporter.go b/pkg/build/nodeimage/imageimporter.go index 7839263fe7..4e6da015c3 100644 --- a/pkg/build/nodeimage/imageimporter.go +++ b/pkg/build/nodeimage/imageimporter.go @@ -55,7 +55,8 @@ func (c *containerdImporter) Pull(image, platform string) error { func (c *containerdImporter) LoadCommand() exec.Cmd { return c.containerCmder.Command( // TODO: ideally we do not need this in the future. we have fixed at least one image - "ctr", "--namespace=k8s.io", "images", "import", "--label=io.cri-containerd.pinned=pinned", "--all-platforms", "--no-unpack", "--digests", "-", + // --local=true: see the comment in pkg/cluster/nodeutils/util.go + "ctr", "--namespace=k8s.io", "images", "import", "--local=true", "--label=io.cri-containerd.pinned=pinned", "--all-platforms", "--no-unpack", "--digests", "-", ) } diff --git a/pkg/cluster/nodeutils/util.go b/pkg/cluster/nodeutils/util.go index 501681a2ce..5dda343c3d 100644 --- a/pkg/cluster/nodeutils/util.go +++ b/pkg/cluster/nodeutils/util.go @@ -19,6 +19,7 @@ package nodeutils import ( "bytes" "encoding/json" + "fmt" "io" "path" "strings" @@ -82,7 +83,9 @@ func LoadImageArchive(n nodes.Node, image io.Reader) error { if err != nil { return err } - cmd := n.Command("ctr", "--namespace=k8s.io", "images", "import", "--all-platforms", "--digests", "--snapshotter="+snapshotter, "-").SetStdin(image) + // --local=true: Disables the Transfer API mode that is enabled by default since containerd v2.0. + // Workaround for `ctr: rpc error: code = InvalidArgument desc = unable to initialize unpacker: no unpack platforms defined: invalid argument` + cmd := n.Command("ctr", "--namespace=k8s.io", "images", "import", "--local=true", "--all-platforms", "--digests", "--snapshotter="+snapshotter, "-").SetStdin(image) if err := cmd.Run(); err != nil { return errors.Wrap(err, "failed to load image") } @@ -102,9 +105,24 @@ func parseSnapshotter(config string) (string, error) { if err != nil { return "", errors.Wrap(err, "failed to detect containerd snapshotter") } - snapshotter, ok := parsed.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "snapshotter"}).(string) + configVersion, ok := parsed.Get("version").(int64) if !ok { - return "", errors.New("failed to detect containerd snapshotter") + return "", errors.New("failed to detect containerd config version") + } + var snapshotter string + switch configVersion { + case 2: // Introduced in containerd v1.3. Still supported in containerd v2. + snapshotter, ok = parsed.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "snapshotter"}).(string) + if !ok { + return "", errors.New("failed to detect containerd snapshotter (config version 2)") + } + case 3: // Introduced in containerd v2.0. + snapshotter, ok = parsed.GetPath([]string{"plugins", "io.containerd.cri.v1.images", "snapshotter"}).(string) + if !ok { + return "", errors.New("failed to detect containerd snapshotter (config version 3)") + } + default: + return "", fmt.Errorf("unknown containerd config version: %d (supported versions: 2 and 3)", configVersion) } return snapshotter, nil }