diff --git a/RELEASES.md b/RELEASES.md index d21f70d17a1de..e526873964e85 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -138,12 +138,14 @@ to all committers. | [1.5](https://github.com/containerd/containerd/releases/tag/v1.5.18) | End of Life | May 3, 2021 | February 28, 2023 | | | [1.6](https://github.com/containerd/containerd/releases/tag/v1.6.39) | End of Life | February 15, 2022 | August 23, 2025 | @containerd/committers | | [1.7](https://github.com/containerd/containerd/releases/tag/v1.7.0) | LTS | March 10, 2023 | September 2026* | [@samuelkarp](https://github.com/samuelkarp), [@chrishenzie](https://github.com/chrishenzie) | -| [2.0](https://github.com/containerd/containerd/releases/tag/v2.0.7) | End of Life | November 5, 2024 | November 7, 2025 | @containerd/committers | +| [2.0](https://github.com/containerd/containerd/releases/tag/v2.0.7) | LTS | November 5, 2024 | March, 2027** | [@samuelkarp](https://github.com/samuelkarp), [@chrishenzie](https://github.com/chrishenzie) | | [2.1](https://github.com/containerd/containerd/releases/tag/v2.1.0) | Active | May 7, 2025 | May 5, 2026 | @containerd/committers | | [2.2](https://github.com/containerd/containerd/releases/tag/v2.2.0) | Active | November 5, 2025 | November 6, 2026 | @containerd/committers | | [2.3](https://github.com/containerd/containerd/milestone/50) | LTS (_future_) | April 27, 2026 (_tentative_) | April 27, 2028 (_tentative_) | @containerd/committers | -\* Support for the 1.7 release branch was provided by @containerd/committers until March 10, 2026. Extended support through September 2026 is provided by [@samuelkarp](https://github.com/samuelkarp) and [@chrishenzie](https://github.com/chrishenzie). This extended support is focused on usage with Kubernetes 1.32, 1.31, and 1.30 via [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine). +\* Support for the 1.7 release branch was provided by @containerd/committers until March 10, 2026. Extended support through September 2026 is provided by [@samuelkarp](https://github.com/samuelkarp) and [@chrishenzie](https://github.com/chrishenzie). This extended support is focused on usage with Kubernetes 1.32, 1.31, and 1.30 via [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine). Changes may not be accepted if they are not needed for this usage. + +\*\* Support for the 2.0 release branch was provided by @containerd/committers until November 7, 2025. Extended support through March 2027 is provided by [@samuelkarp](https://github.com/samuelkarp) and [@chrishenzie](https://github.com/chrishenzie). This extended support is focused on usage with Kuberentes 1.33 via [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine). Changes may not be accepted if they are not needed for this usage. ### Kubernetes Support diff --git a/core/remotes/docker/pusher.go b/core/remotes/docker/pusher.go index 4ab15bba8378d..900389a0fb143 100644 --- a/core/remotes/docker/pusher.go +++ b/core/remotes/docker/pusher.go @@ -117,6 +117,9 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str } req := p.request(host, http.MethodHead, existCheck...) + if err := req.addNamespace(p.refspec.Hostname()); err != nil { + return nil, err + } req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", ")) log.G(ctx).WithField("url", req.sanitizedURL()).Debugf("checking and pushing to") @@ -165,10 +168,16 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str if isManifest { putPath := getManifestPath(p.object, desc.Digest) req = p.request(host, http.MethodPut, putPath...) + if err := req.addNamespace(p.refspec.Hostname()); err != nil { + return nil, err + } req.header.Add("Content-Type", desc.MediaType) } else { // Start upload request req = p.request(host, http.MethodPost, "blobs", "uploads/") + if err := req.addNamespace(p.refspec.Hostname()); err != nil { + return nil, err + } mountedFrom := "" var resp *http.Response @@ -273,6 +282,9 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str req = p.request(lhost, http.MethodPut) req.header.Set("Content-Type", "application/octet-stream") req.path = lurl.Path + "?" + q.Encode() + if err := req.addNamespace(p.refspec.Hostname()); err != nil { + return nil, err + } } p.tracker.SetStatus(ref, Status{ Status: content.Status{ diff --git a/core/remotes/docker/pusher_test.go b/core/remotes/docker/pusher_test.go index c6e217a5b5224..9a68f93c31894 100644 --- a/core/remotes/docker/pusher_test.go +++ b/core/remotes/docker/pusher_test.go @@ -93,6 +93,23 @@ func TestPusherErrClosedRetry(t *testing.T) { t.Errorf("upload should succeed but got %v", err) } } +func TestPusherCustomNamespace(t *testing.T) { + ctx := context.Background() + p, reg, _, done := samplePusher(t) + defer done() + + reg.uploadable = true + reg.putHandlerFunc = func(w http.ResponseWriter, r *http.Request) bool { + if r.URL.Path == "/upload" { + reg.lastPutQueryParams = r.URL.Query() + } + return false + } + + assert.Nil(t, tryUpload(ctx, t, p, []byte("test"))) + assert.Equal(t, samplePusherHostname, reg.lastPutQueryParams.Get("ns")) + assert.NotEmpty(t, reg.lastPutQueryParams.Get("digest")) +} func TestPusherAcceptsMissingDigestHeader(t *testing.T) { ctx := context.Background() @@ -432,6 +449,7 @@ type uploadableMockRegistry struct { locationPrefix string username string secret string + lastPutQueryParams url.Values // Track query params from last PUT request } func (u *uploadableMockRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request) {