cri: deprecate restore in CreateContainer

Assisted-by: Antigravity
Signed-off-by: Samuel Karp <samuelkarp@google.com>
This commit is contained in:
Samuel Karp
2026-07-24 07:42:54 +00:00
parent ffcf715dfa
commit a3f99ba690
7 changed files with 151 additions and 19 deletions

View File

@@ -601,18 +601,19 @@ 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+prettyjws`) | 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) |
| NRI v0.1.0 plugin support | containerd v2.2 | containerd v2.3 | Use the v010-adapter NRI plugin, or update v0.1.0 plugins to use the current NRI API |
| cgroup v1 support | containerd v2.2 | (May 2029) | Use cgroup v2 |
|----------------------------------------------------------------------------------|---------------------|---------------------------------------|------------------------------------------------------------------------------------------------|
| 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+prettyjws`) | 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) |
| NRI v0.1.0 plugin support | containerd v2.2 | containerd v2.3 | Use the v010-adapter NRI plugin, or update v0.1.0 plugins to use the current NRI API |
| cgroup v1 support | containerd v2.2 | (May 2029) | Use cgroup v2 |
| Restoring checkpoint data during CRI `CreateContainer` | containerd v2.3 | containerd v2.4 | Follow [KEP-5823](https://github.com/kubernetes/enhancements/issues/5823) for a replacement `RestorePod` API |
- 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`). Users of CRI clients (such as Kubernetes and `crictl`) have to specify this environment variable on the containerd daemon (usually in the systemd unit).

View File

@@ -126,6 +126,12 @@ function test_from_archive() {
echo "error: CDI annotation was not filtered or safe annotation missing: $actual_annots"
exit 1
fi
echo "--> Verifying deprecation warning via API (archive): "
archive_ts=$(../../bin/ctr deprecations list --format=json | jq -r '.[] | select(.id == "io.containerd.deprecation/cri-create-container-checkpoint-restore") | .lastOccurrence')
if [ -z "$archive_ts" ] || [ "$archive_ts" = "null" ]; then
echo "error: CRICreateContainerCheckpointRestore deprecation warning not found in API introspection (archive)"
exit 1
fi
# Cleanup
echo "--> Cleanup images: "
(crictl rmi "${TEST_IMAGE}" || true) | sed 's/^/----> \t/'
@@ -198,6 +204,16 @@ function test_from_oci() {
rm -f "$RESTORE_JSON" "$RESTORE_POD_JSON"
echo -n "--> Start container from checkpoint: "
crictl start "$ctr_id"
echo "--> Verifying deprecation warning via API (oci): "
oci_ts=$(../../bin/ctr deprecations list --format=json | jq -r '.[] | select(.id == "io.containerd.deprecation/cri-create-container-checkpoint-restore") | .lastOccurrence')
if [ -z "$oci_ts" ] || [ "$oci_ts" = "null" ]; then
echo "error: CRICreateContainerCheckpointRestore deprecation warning not found in API introspection (oci)"
exit 1
fi
if [ "$archive_ts" = "$oci_ts" ]; then
echo "error: expected lastOccurrence to update after OCI restore (was $archive_ts, now $oci_ts)"
exit 1
fi
# Cleanup
echo "--> Cleanup images: "
../../bin/ctr -n k8s.io images rm localhost/checkpoint-image:latest | sed 's/^/----> \t/'

View File

@@ -0,0 +1,91 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package server
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/containerd/v2/core/sandbox"
sandboxstore "github.com/containerd/containerd/v2/internal/cri/store/sandbox"
"github.com/containerd/containerd/v2/pkg/deprecation"
"github.com/containerd/containerd/v2/plugins/services/warning"
)
type mockWarningService struct {
emitted []deprecation.Warning
}
func (m *mockWarningService) Emit(ctx context.Context, w deprecation.Warning) {
m.emitted = append(m.emitted, w)
}
func (m *mockWarningService) Warnings() []warning.Warning {
return nil
}
type testSandboxService struct {
fakeSandboxService
}
func (t *testSandboxService) SandboxStatus(ctx context.Context, sandboxer string, sandboxID string, verbose bool) (sandbox.ControllerStatus, error) {
return sandbox.ControllerStatus{
SandboxID: sandboxID,
Pid: 1234,
State: "READY",
}, nil
}
func TestCreateContainerCheckpointWarning(t *testing.T) {
c := newTestCRIService()
mockWarn := &mockWarningService{}
c.warningService = mockWarn
c.sandboxService = &testSandboxService{}
sb := sandboxstore.NewSandbox(
sandboxstore.Metadata{
ID: "test-sandbox",
Name: "test-sandbox",
Config: &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{Name: "test-sandbox", Namespace: "default"},
},
},
sandboxstore.Status{
State: sandboxstore.StateReady,
},
)
require.NoError(t, c.sandboxStore.Add(sb))
// In newTestCRIService(), c.os is a FakeOS where Stat returns (nil, nil) (no error),
// causing checkpointImage to evaluate as true when checked in CreateContainer.
_, _ = c.CreateContainer(context.Background(), &runtime.CreateContainerRequest{
PodSandboxId: "test-sandbox",
Config: &runtime.ContainerConfig{
Metadata: &runtime.ContainerMetadata{Name: "test-container"},
Image: &runtime.ImageSpec{Image: "/path/to/checkpoint.tar"},
},
SandboxConfig: &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{Name: "test-sandbox", Namespace: "default"},
},
})
assert.Contains(t, mockWarn.emitted, deprecation.CRICreateContainerCheckpointRestore, "expected CRICreateContainerCheckpointRestore deprecation warning to be emitted")
}

View File

@@ -47,6 +47,7 @@ import (
"github.com/containerd/containerd/v2/internal/cri/util"
"github.com/containerd/containerd/v2/internal/registrar"
"github.com/containerd/containerd/v2/pkg/blockio"
"github.com/containerd/containerd/v2/pkg/deprecation"
"github.com/containerd/containerd/v2/pkg/oci"
"github.com/containerd/containerd/v2/pkg/tracing"
)
@@ -153,6 +154,17 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
// This might be a checkpoint image. Let's pass
// it to the checkpoint code.
if c.warningService != nil {
c.warningService.Emit(ctx, deprecation.CRICreateContainerCheckpointRestore)
if msg, ok := deprecation.Message(deprecation.CRICreateContainerCheckpointRestore); ok {
log.G(ctx).WithFields(log.Fields{
"podsandboxid": sandboxID,
"containerid": id,
"containername": name,
}).Warn(msg)
}
}
if sandboxConfig.GetMetadata() == nil {
return nil, fmt.Errorf("sandboxConfig must not be empty")
}

View File

@@ -57,6 +57,7 @@ import (
"github.com/containerd/containerd/v2/pkg/oci"
osinterface "github.com/containerd/containerd/v2/pkg/os"
"github.com/containerd/containerd/v2/plugins"
"github.com/containerd/containerd/v2/plugins/services/warning"
)
var kernelSupportsRRO bool
@@ -171,6 +172,8 @@ type criService struct {
statsCollector *StatsCollector
// shimPath is the custom PATH environment variable value from the shim manager
shimPath string
// warningService is used to emit deprecation warnings.
warningService warning.Service
checkCriuOnce sync.Once //nolint:nolintlint,unused // Ignore on non-Linux
checkCriuErr error //nolint:nolintlint,unused // Ignore on non-Linux
@@ -195,6 +198,9 @@ type CRIServiceOptions struct {
// ShimPath is the custom PATH environment variable value from the shim manager
ShimPath string
// WarningService is used to emit deprecation warnings.
WarningService warning.Service
}
// NewCRIService returns a new instance of CRIService
@@ -223,6 +229,7 @@ func NewCRIService(options *CRIServiceOptions) (CRIService, runtime.RuntimeServi
runtimeHandlers: make(map[string]*runtime.RuntimeHandler),
statsCollector: statsCollector,
shimPath: options.ShimPath,
warningService: options.WarningService,
}
// TODO: Make discard time configurable

View File

@@ -43,6 +43,8 @@ const (
RuncOptionsTaskAPIAddress Warning = Prefix + "runc-options-task-api-address"
// RuncOptionsTaskAPIVersion is a warning for the use of `task_api_version` in runc options
RuncOptionsTaskAPIVersion Warning = Prefix + "runc-options-task-api-version"
// CRICreateContainerCheckpointRestore is a warning for restoring checkpoint data from an image or archive during CRI CreateContainer
CRICreateContainerCheckpointRestore Warning = Prefix + "cri-create-container-checkpoint-restore"
)
const (
@@ -67,8 +69,9 @@ var messages = map[Warning]string{
CgroupV1: "The support for cgroup v1 is deprecated since containerd v2.2 and will be removed by no later than May 2029. Upgrade the host to use cgroup v2.",
CRIEnableCDI: "The `enable_cdi` property of `[plugins.\"io.containerd.cri.v1.runtime\"]` is deprecated, will be removed in containerd v2.3, and CDI support will always be enabled.",
RuncOptionsTaskAPIAddress: "The `task_api_address` field in runc options is deprecated since containerd v2.3. Set `task_api_address` on CreateTaskRequest instead.",
RuncOptionsTaskAPIVersion: "The `task_api_version` field in runc options is deprecated since containerd v2.3. Set `task_api_version` on CreateTaskRequest instead.",
RuncOptionsTaskAPIAddress: "The `task_api_address` field in runc options is deprecated since containerd v2.3. Set `task_api_address` on CreateTaskRequest instead.",
RuncOptionsTaskAPIVersion: "The `task_api_version` field in runc options is deprecated since containerd v2.3. Set `task_api_version` on CreateTaskRequest instead.",
CRICreateContainerCheckpointRestore: "Restoring checkpoint data from an image or archive during CRI CreateContainer is deprecated and will be removed in containerd v2.4.",
}
// Valid checks whether a given Warning is valid

View File

@@ -99,14 +99,15 @@ func initCRIService(ic *plugin.InitContext) (any, error) {
}
}
ws, err := ic.GetSingle(plugins.WarningPlugin)
if err != nil {
return nil, err
}
warn := ws.(warning.Service)
if warnings, err := criconfig.ValidateServerConfig(ic.Context, config); err != nil {
return nil, fmt.Errorf("invalid cri image config: %w", err)
} else if len(warnings) > 0 {
ws, err := ic.GetSingle(plugins.WarningPlugin)
if err != nil {
return nil, err
}
warn := ws.(warning.Service)
for _, w := range warnings {
warn.Emit(ic.Context, w)
}
@@ -157,6 +158,7 @@ func initCRIService(ic *plugin.InitContext) (any, error) {
Client: client,
SandboxControllers: sbControllers,
ShimPath: shimPath,
WarningService: warn,
}
is := criImagePlugin.(imageService).GRPCService()