From 99721c27e17706a322b04d390adce06485e5d4f5 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 13 Feb 2024 00:38:50 +0900 Subject: [PATCH] Disable the support for Schema 1 images Schema 1 (`application/vnd.docker.distribution.manifest.v1+prettyjws`) has been officially deprecated since containerd v1.7 (PR 6884). We have planned to remove the support for Schema 1 in containerd v2.0, but this removal may still surprise some users. So, in containerd v2.0 we will just disable it by default. The support for Schema 1 can be still enabled by setting an environment variable `CONTAINERD_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE=1`, however, this workaround will be completely removed in containerd v2.1. Schema 2 was introduced in Docker 1.10 (Feb 2016), so most users should have been already using Schema 2 or OCI. Signed-off-by: Akihiro Suda --- RELEASES.md | 26 +++++++++++++----------- client/pull.go | 5 ++++- core/remotes/docker/schema1/converter.go | 22 ++++++++++++++++++-- integration/client/client_test.go | 2 ++ integration/client/client_unix_test.go | 2 ++ integration/containerd_image_test.go | 2 ++ pkg/deprecation/deprecation.go | 7 ++++++- 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 32c52e936dc5..3f008679aa67 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -396,18 +396,20 @@ against total impact. The deprecated features are shown in the following table: -| Component | Deprecation release | Target release for removal | Recommendation | -|----------------------------------------------------------------------------------|---------------------|----------------------------|------------------------------------------| -| Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | -| Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | -| Built-in `aufs` snapshotter | containerd v1.5 | containerd v2.0 ✅ | Use `overlayfs` snapshotter | -| Container label `containerd.io/restart.logpath` | containerd v1.5 | containerd v2.0 ✅ | Use `containerd.io/restart.loguri` label | -| `cri-containerd-*.tar.gz` release bundles | containerd v1.6 | containerd v2.0 ✅ | Use `containerd-*.tar.gz` bundles | -| Pulling Schema 1 images (`application/vnd.docker.distribution.manifest.v1+json`) | containerd v1.7 | containerd v2.0 | Use Schema 2 or OCI images | -| CRI `v1alpha2` | containerd v1.7 | containerd v2.0 ✅ | Use CRI `v1` | -| Legacy CRI implementation of podsandbox support | containerd v2.0 | containerd v2.0 ✅ | | -| Go-Plugin library (`*.so`) as containerd runtime plugin | containerd v2.0 | containerd v2.1 | Use external plugins (proxy or binary) | - +| Component | Deprecation release | Target release for removal | Recommendation | +|----------------------------------------------------------------------------------|---------------------|---------------------------------------|------------------------------------------| +| Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | +| Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | +| Built-in `aufs` snapshotter | containerd v1.5 | containerd v2.0 ✅ | Use `overlayfs` snapshotter | +| Container label `containerd.io/restart.logpath` | containerd v1.5 | containerd v2.0 ✅ | Use `containerd.io/restart.loguri` label | +| `cri-containerd-*.tar.gz` release bundles | containerd v1.6 | containerd v2.0 ✅ | Use `containerd-*.tar.gz` bundles | +| Pulling Schema 1 images (`application/vnd.docker.distribution.manifest.v1+json`) | containerd v1.7 | containerd v2.1 (Disabled in v2.0 ✅) | Use Schema 2 or OCI images | +| CRI `v1alpha2` | containerd v1.7 | containerd v2.0 ✅ | Use CRI `v1` | +| Legacy CRI implementation of podsandbox support | containerd v2.0 | containerd v2.0 ✅ | | +| Go-Plugin library (`*.so`) as containerd runtime plugin | containerd v2.0 | containerd v2.1 | Use external plugins (proxy or binary) | + +- Pulling Schema 1 images has been disabled in containerd v2.0, but it still can be enabled by setting an environment variable `CONTAINERD_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE=1` + until containerd v2.1. `ctr` users have to specify `--local` too (e.g., `ctr images pull --local`). ### Deprecated config properties The deprecated properties in [`config.toml`](./docs/cri/config.md) are shown in the following table: diff --git a/client/pull.go b/client/pull.go index 6908fee9c89c..060c729dfea1 100644 --- a/client/pull.go +++ b/client/pull.go @@ -197,7 +197,10 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim ) if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 { - schema1Converter := schema1.NewConverter(store, fetcher) + schema1Converter, err := schema1.NewConverter(store, fetcher) + if err != nil { + return images.Image{}, fmt.Errorf("failed to get converter for %q: %w", ref, err) + } handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...) diff --git a/core/remotes/docker/schema1/converter.go b/core/remotes/docker/schema1/converter.go index e8a3534ddd05..e724e4e55abc 100644 --- a/core/remotes/docker/schema1/converter.go +++ b/core/remotes/docker/schema1/converter.go @@ -27,6 +27,7 @@ import ( "errors" "fmt" "io" + "os" "strconv" "strings" "sync" @@ -36,6 +37,7 @@ import ( "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/remotes" "github.com/containerd/containerd/v2/pkg/archive/compression" + "github.com/containerd/containerd/v2/pkg/deprecation" "github.com/containerd/containerd/v2/pkg/labels" "github.com/containerd/errdefs" "github.com/containerd/log" @@ -67,14 +69,30 @@ type Converter struct { layerBlobs map[digest.Digest]ocispec.Descriptor } +var ErrDisabled = fmt.Errorf("Pulling Schema 1 images have been deprecated and disabled by default since containerd v2.0. "+ + "As a workaround you may set an environment variable `%s=1`, but this will be completely removed in containerd v2.1.", + deprecation.EnvPullSchema1Image) + // NewConverter returns a new converter -func NewConverter(contentStore content.Store, fetcher remotes.Fetcher) *Converter { +func NewConverter(contentStore content.Store, fetcher remotes.Fetcher) (*Converter, error) { + s := os.Getenv(deprecation.EnvPullSchema1Image) + if s == "" { + return nil, ErrDisabled + } + enable, err := strconv.ParseBool(s) + if err != nil { + return nil, fmt.Errorf("failed to parse `%s=%s`: %w", deprecation.EnvPullSchema1Image, s, err) + } + if !enable { + return nil, ErrDisabled + } + log.L.Warn(ErrDisabled) return &Converter{ contentStore: contentStore, fetcher: fetcher, blobMap: map[digest.Digest]blobState{}, layerBlobs: map[digest.Digest]ocispec.Descriptor{}, - } + }, nil } // Handle fetching descriptors for a docker media type diff --git a/integration/client/client_test.go b/integration/client/client_test.go index 691d07c7af95..7e0fb208cb7a 100644 --- a/integration/client/client_test.go +++ b/integration/client/client_test.go @@ -40,6 +40,7 @@ import ( "github.com/containerd/containerd/v2/defaults" imagelist "github.com/containerd/containerd/v2/integration/images" "github.com/containerd/containerd/v2/internal/testutil" + "github.com/containerd/containerd/v2/pkg/deprecation" "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/errdefs" "github.com/containerd/log" @@ -422,6 +423,7 @@ func TestImagePullSomePlatforms(t *testing.T) { } func TestImagePullSchema1(t *testing.T) { + t.Setenv(deprecation.EnvPullSchema1Image, "1") client, err := newClient(t, address) if err != nil { t.Fatal(err) diff --git a/integration/client/client_unix_test.go b/integration/client/client_unix_test.go index 59bea46a255f..44c81ecce218 100644 --- a/integration/client/client_unix_test.go +++ b/integration/client/client_unix_test.go @@ -23,6 +23,7 @@ import ( . "github.com/containerd/containerd/v2/client" "github.com/containerd/containerd/v2/integration/images" + "github.com/containerd/containerd/v2/pkg/deprecation" "github.com/containerd/platforms" ) @@ -46,6 +47,7 @@ var ( ) func TestImagePullSchema1WithEmptyLayers(t *testing.T) { + t.Setenv(deprecation.EnvPullSchema1Image, "1") client, err := newClient(t, address) if err != nil { t.Fatal(err) diff --git a/integration/containerd_image_test.go b/integration/containerd_image_test.go index f56c0820aef6..af16e602d60e 100644 --- a/integration/containerd_image_test.go +++ b/integration/containerd_image_test.go @@ -28,6 +28,7 @@ import ( containerd "github.com/containerd/containerd/v2/client" "github.com/containerd/containerd/v2/integration/images" "github.com/containerd/containerd/v2/internal/cri/labels" + "github.com/containerd/containerd/v2/pkg/deprecation" "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/errdefs" "github.com/stretchr/testify/assert" @@ -267,6 +268,7 @@ func TestContainerdSandboxImagePulledOutsideCRI(t *testing.T) { } func TestContainerdImageWithDockerSchema1(t *testing.T) { + t.Setenv(deprecation.EnvPullSchema1Image, "1") if goruntime.GOOS == "windows" { t.Skip("Skipped on Windows because the test image is not a multi-platform one.") } diff --git a/pkg/deprecation/deprecation.go b/pkg/deprecation/deprecation.go index 9b85e2d0b114..64723a7b27a6 100644 --- a/pkg/deprecation/deprecation.go +++ b/pkg/deprecation/deprecation.go @@ -33,8 +33,13 @@ const ( CRIRegistryConfigs Warning = Prefix + "cri-registry-configs" ) +const ( + EnvPrefix = "CONTAINERD_ENABLE_DEPRECATED_" + EnvPullSchema1Image = EnvPrefix + "PULL_SCHEMA_1_IMAGE" +) + var messages = map[Warning]string{ - PullSchema1Image: "Schema 1 images are deprecated since containerd v1.7 and removed in containerd v2.0. " + + PullSchema1Image: "Schema 1 images are deprecated since containerd v1.7, disabled in containerd v2.0, and will be removed in containerd v2.1. " + `Since containerd v1.7.8, schema 1 images are identified by the "io.containerd.image/converted-docker-schema1" label.`, GoPluginLibrary: "Dynamically-linked Go plugins as containerd runtimes are deprecated since containerd v2.0 and removed in containerd v2.1.", CRIRegistryMirrors: "The `mirrors` property of `[plugins.\"io.containerd.grpc.v1.cri\".registry]` is deprecated since containerd v1.5 and will be removed in containerd v2.0." +