Skip to content

Commit 3baf5ed

Browse files
committed
Separate the CRI image config from the main plugin config
This change simplifies the CRI plugin dependencies by not requiring the CRI image plugin to depend on any other CRI components. Since other CRI plugins depend on the image plugin, this allows prevents a dependency cycle for CRI configurations on a base plugin. Signed-off-by: Derek McGowan <[email protected]>
1 parent ad4c9f8 commit 3baf5ed

File tree

16 files changed

+454
-362
lines changed

16 files changed

+454
-362
lines changed

cmd/containerd/builtins/cri.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ package builtins
2020

2121
import (
2222
_ "github.com/containerd/containerd/v2/pkg/cri"
23+
_ "github.com/containerd/containerd/v2/plugins/cri/images"
2324
)

integration/build_local_containerd_helper_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
_ "github.com/containerd/containerd/v2/gc/scheduler"
4040
_ "github.com/containerd/containerd/v2/leases/plugin"
4141
_ "github.com/containerd/containerd/v2/metadata/plugin"
42+
_ "github.com/containerd/containerd/v2/plugins/cri/images"
4243
_ "github.com/containerd/containerd/v2/runtime/v2"
4344
_ "github.com/containerd/containerd/v2/runtime/v2/runc/options"
4445
_ "github.com/containerd/containerd/v2/services/containers"
@@ -53,7 +54,7 @@ import (
5354
_ "github.com/containerd/containerd/v2/services/tasks"
5455
_ "github.com/containerd/containerd/v2/services/version"
5556

56-
"github.com/stretchr/testify/assert"
57+
"github.com/stretchr/testify/require"
5758
)
5859

5960
var (
@@ -72,7 +73,7 @@ func buildLocalContainerdClient(t *testing.T, tmpDir string, tweakInitFn tweakPl
7273
// load plugins
7374
loadPluginOnce.Do(func() {
7475
loadedPlugins, loadedPluginsErr = ctrdsrv.LoadPlugins(ctx, &srvconfig.Config{})
75-
assert.NoError(t, loadedPluginsErr)
76+
require.NoError(t, loadedPluginsErr)
7677
})
7778

7879
// init plugins
@@ -104,7 +105,7 @@ func buildLocalContainerdClient(t *testing.T, tmpDir string, tweakInitFn tweakPl
104105
// load the plugin specific configuration if it is provided
105106
if p.Config != nil {
106107
pc, err := config.Decode(ctx, p.URI(), p.Config)
107-
assert.NoError(t, err)
108+
require.NoError(t, err)
108109

109110
initContext.Config = pc
110111
}
@@ -114,10 +115,10 @@ func buildLocalContainerdClient(t *testing.T, tmpDir string, tweakInitFn tweakPl
114115
}
115116

116117
result := p.Init(initContext)
117-
assert.NoError(t, initialized.Add(result))
118+
require.NoError(t, initialized.Add(result))
118119

119120
_, err := result.Instance()
120-
assert.NoError(t, err)
121+
require.NoError(t, err)
121122

122123
lastInitContext = initContext
123124
}
@@ -129,7 +130,7 @@ func buildLocalContainerdClient(t *testing.T, tmpDir string, tweakInitFn tweakPl
129130
containerd.WithInMemoryServices(lastInitContext),
130131
containerd.WithInMemorySandboxControllers(lastInitContext),
131132
)
132-
assert.NoError(t, err)
133+
require.NoError(t, err)
133134

134135
return client
135136
}

pkg/cri/config/config.go

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ const (
6767
ModePodSandbox SandboxControllerMode = "podsandbox"
6868
// ModeShim means use whatever Controller implementation provided by shim.
6969
ModeShim SandboxControllerMode = "shim"
70+
// DefaultSandboxImage is the default image to use for sandboxes when empty or
71+
// for default configurations.
72+
DefaultSandboxImage = "registry.k8s.io/pause:3.9"
7073
)
7174

7275
// Runtime struct to contain the type(ID), engine, and root variables for a default runtime
@@ -242,8 +245,12 @@ type ImageDecryption struct {
242245
// can be assumed. When platform is not provided, the default platform can
243246
// be assumed
244247
type ImagePlatform struct {
245-
Platform string
246-
Snapshotter string
248+
Platform string `toml:"platform" json:"platform"`
249+
// Snapshotter setting snapshotter at runtime level instead of making it as a global configuration.
250+
// An example use case is to use devmapper or other snapshotters in Kata containers for performance and security
251+
// while using default snapshotters for operational simplicity.
252+
// See https://github.com/containerd/containerd/issues/6657 for details.
253+
Snapshotter string `toml:"snapshotter" json:"snapshotter"`
247254
}
248255

249256
type ImageConfig struct {
@@ -261,18 +268,21 @@ type ImageConfig struct {
261268
DiscardUnpackedLayers bool `toml:"discard_unpacked_layers" json:"discardUnpackedLayers"`
262269

263270
// PinnedImages are images which the CRI plugin uses and should not be
264-
// removed by the CRI client.
271+
// removed by the CRI client. The images have a key which can be used
272+
// by other plugins to lookup the current image name.
265273
// Image names should be full names including domain and tag
266274
// Examples:
267-
// docker.io/library/ubuntu:latest
268-
// images.k8s.io/core/pause:1.55
269-
PinnedImages []string
275+
// "sandbox": "k8s.gcr.io/pause:3.9"
276+
// "base": "docker.io/library/ubuntu:latest"
277+
// Migrated from:
278+
// (PluginConfig).SandboxImage string `toml:"sandbox_image" json:"sandboxImage"`
279+
PinnedImages map[string]string
270280

271281
// RuntimePlatforms is map between the runtime and the image platform to
272282
// use for that runtime. When resolving an image for a runtime, this
273283
// mapping will be used to select the image for the platform and the
274284
// snapshotter for unpacking.
275-
RuntimePlatforms map[string]ImagePlatform
285+
RuntimePlatforms map[string]ImagePlatform `toml:"runtime_platforms" json:"runtimePlatforms"`
276286

277287
// Registry contains config related to the registry
278288
Registry Registry `toml:"registry" json:"registry"`
@@ -305,8 +315,6 @@ type ImageConfig struct {
305315
// PluginConfig contains toml config related to CRI plugin,
306316
// it is a subset of Config.
307317
type PluginConfig struct {
308-
// ImageConfig is the image service configuration
309-
ImageConfig
310318
// ContainerdConfig contains config related to containerd
311319
ContainerdConfig `toml:"containerd" json:"containerd"`
312320
// CniConfig contains config related to cni
@@ -327,8 +335,6 @@ type PluginConfig struct {
327335
// SelinuxCategoryRange allows the upper bound on the category range to be set.
328336
// If not specified or set to 0, defaults to 1024 from the selinux package.
329337
SelinuxCategoryRange int `toml:"selinux_category_range" json:"selinuxCategoryRange"`
330-
// SandboxImage is the image used by sandbox container.
331-
SandboxImage string `toml:"sandbox_image" json:"sandboxImage"`
332338
// EnableTLSStreaming indicates to enable the TLS streaming support.
333339
EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"`
334340
// X509KeyPairStreaming is a x509 key pair used for TLS streaming
@@ -437,31 +443,9 @@ const (
437443
KeyModelNode = "node"
438444
)
439445

440-
// ValidatePluginConfig validates the given plugin configuration.
441-
func ValidatePluginConfig(ctx context.Context, c *PluginConfig) ([]deprecation.Warning, error) {
446+
// ValidateImageConfig validates the given image configuration
447+
func ValidateImageConfig(ctx context.Context, c *ImageConfig) ([]deprecation.Warning, error) {
442448
var warnings []deprecation.Warning
443-
if c.ContainerdConfig.Runtimes == nil {
444-
c.ContainerdConfig.Runtimes = make(map[string]Runtime)
445-
}
446-
447-
// Validation for default_runtime_name
448-
if c.ContainerdConfig.DefaultRuntimeName == "" {
449-
return warnings, errors.New("`default_runtime_name` is empty")
450-
}
451-
if _, ok := c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName]; !ok {
452-
return warnings, fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName)
453-
}
454-
455-
for k, r := range c.ContainerdConfig.Runtimes {
456-
if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed {
457-
return warnings, errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled")
458-
}
459-
// If empty, use default podSandbox mode
460-
if len(r.Sandboxer) == 0 {
461-
r.Sandboxer = string(ModePodSandbox)
462-
c.ContainerdConfig.Runtimes[k] = r
463-
}
464-
}
465449

466450
useConfigPath := c.Registry.ConfigPath != ""
467451
if len(c.Registry.Mirrors) > 0 {
@@ -500,20 +484,49 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) ([]deprecation.W
500484
log.G(ctx).Warning("`auths` is deprecated, please use `ImagePullSecrets` instead")
501485
}
502486

503-
// Validation for stream_idle_timeout
504-
if c.StreamIdleTimeout != "" {
505-
if _, err := time.ParseDuration(c.StreamIdleTimeout); err != nil {
506-
return warnings, fmt.Errorf("invalid stream idle timeout: %w", err)
507-
}
508-
}
509-
510487
// Validation for image_pull_progress_timeout
511488
if c.ImagePullProgressTimeout != "" {
512489
if _, err := time.ParseDuration(c.ImagePullProgressTimeout); err != nil {
513490
return warnings, fmt.Errorf("invalid image pull progress timeout: %w", err)
514491
}
515492
}
516493

494+
return warnings, nil
495+
}
496+
497+
// ValidatePluginConfig validates the given plugin configuration.
498+
func ValidatePluginConfig(ctx context.Context, c *PluginConfig) ([]deprecation.Warning, error) {
499+
var warnings []deprecation.Warning
500+
if c.ContainerdConfig.Runtimes == nil {
501+
c.ContainerdConfig.Runtimes = make(map[string]Runtime)
502+
}
503+
504+
// Validation for default_runtime_name
505+
if c.ContainerdConfig.DefaultRuntimeName == "" {
506+
return warnings, errors.New("`default_runtime_name` is empty")
507+
}
508+
if _, ok := c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName]; !ok {
509+
return warnings, fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName)
510+
}
511+
512+
for k, r := range c.ContainerdConfig.Runtimes {
513+
if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed {
514+
return warnings, errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled")
515+
}
516+
// If empty, use default podSandbox mode
517+
if len(r.Sandboxer) == 0 {
518+
r.Sandboxer = string(ModePodSandbox)
519+
c.ContainerdConfig.Runtimes[k] = r
520+
}
521+
}
522+
523+
// Validation for stream_idle_timeout
524+
if c.StreamIdleTimeout != "" {
525+
if _, err := time.ParseDuration(c.StreamIdleTimeout); err != nil {
526+
return warnings, fmt.Errorf("invalid stream idle timeout: %w", err)
527+
}
528+
}
529+
517530
// Validation for drain_exec_sync_io_timeout
518531
if c.DrainExecSyncIOTimeout != "" {
519532
if _, err := time.ParseDuration(c.DrainExecSyncIOTimeout); err != nil {

0 commit comments

Comments
 (0)