diff --git a/api/types/types.go b/api/types/types.go index a6ed75de3e..dd5f2aff8a 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -511,6 +511,16 @@ type Checkpoint struct { type Runtime struct { Path string `json:"path"` Args []string `json:"runtimeArgs,omitempty"` + + // This is exposed here only for internal use + // It is not currently supported to specify custom shim configs + Shim *ShimConfig `json:"-"` +} + +// ShimConfig is used by runtime to configure containerd shims +type ShimConfig struct { + Binary string + Opts interface{} } // DiskUsage contains response of Engine API: diff --git a/daemon/config/config.go b/daemon/config/config.go index 26614d37c4..bcecd36356 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -36,9 +36,6 @@ const ( // maximum number of attempts that // may take place at a time for each pull when the connection is lost. DefaultDownloadAttempts = 5 - // StockRuntimeName is the reserved name/alias used to represent the - // OCI runtime being shipped with the docker daemon package. - StockRuntimeName = "runc" // DefaultShmSize is the default value for container's shm size DefaultShmSize = int64(67108864) // DefaultNetworkMtu is the default value for network MTU @@ -47,8 +44,24 @@ const ( DisableNetworkBridge = "none" // DefaultInitBinary is the name of the default init binary DefaultInitBinary = "docker-init" + + // StockRuntimeName is the reserved name/alias used to represent the + // OCI runtime being shipped with the docker daemon package. + StockRuntimeName = "runc" + // LinuxV1RuntimeName is the runtime used to specify the containerd v1 shim with the runc binary + // Note this is different than io.containerd.runc.v1 which would be the v1 shim using the v2 shim API. + // This is specifically for the v1 shim using the v1 shim API. + LinuxV1RuntimeName = "io.containerd.runtime.v1.linux" + // LinuxV2RuntimeName is the runtime used to specify the containerd v2 runc shim + LinuxV2RuntimeName = "io.containerd.runc.v2" ) +var builtinRuntimes = map[string]bool{ + StockRuntimeName: true, + LinuxV1RuntimeName: true, + LinuxV2RuntimeName: true, +} + // flatOptions contains configuration keys // that MUST NOT be parsed as deep structures. // Use this to differentiate these options @@ -571,10 +584,12 @@ func Validate(config *Config) error { return err } - if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != StockRuntimeName { - runtimes := config.GetAllRuntimes() - if _, ok := runtimes[defaultRuntime]; !ok { - return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime) + if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" { + if !builtinRuntimes[defaultRuntime] { + runtimes := config.GetAllRuntimes() + if _, ok := runtimes[defaultRuntime]; !ok { + return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime) + } } } diff --git a/daemon/daemon.go b/daemon/daemon.go index 3ea3069888..98c852b425 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -932,7 +932,11 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S } } - return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, d.useShimV2()) + var rt types.Runtime + if runtime := config.GetRuntime(config.GetDefaultRuntimeName()); runtime != nil { + rt = *runtime + } + return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, rt) } // Plugin system initialization should happen before restore. Do not change order. @@ -1081,7 +1085,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S go d.execCommandGC() - d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d, d.useShimV2()) + d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d) if err != nil { return nil, err } diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 58fa4eeb65..cb058512ae 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -30,7 +30,6 @@ import ( "github.com/docker/docker/opts" "github.com/docker/docker/pkg/containerfs" "github.com/docker/docker/pkg/idtools" - "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/sysinfo" @@ -78,10 +77,6 @@ const ( cgroupFsDriver = "cgroupfs" cgroupSystemdDriver = "systemd" cgroupNoneDriver = "none" - - // DefaultRuntimeName is the default runtime to be used by - // containerd if none is specified - DefaultRuntimeName = "runc" ) type containerGetter interface { @@ -729,57 +724,13 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. } } + if hostConfig.Runtime == config.LinuxV1RuntimeName || (hostConfig.Runtime == "" && daemon.configStore.DefaultRuntime == config.LinuxV1RuntimeName) { + warnings = append(warnings, fmt.Sprintf("Configured runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName)) + } + return warnings, nil } -func (daemon *Daemon) loadRuntimes() error { - return daemon.initRuntimes(daemon.configStore.Runtimes) -} - -func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) { - runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes") - // Remove old temp directory if any - os.RemoveAll(runtimeDir + "-old") - tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes") - if err != nil { - return errors.Wrap(err, "failed to get temp dir to generate runtime scripts") - } - defer func() { - if err != nil { - if err1 := os.RemoveAll(tmpDir); err1 != nil { - logrus.WithError(err1).WithField("dir", tmpDir). - Warn("failed to remove tmp dir") - } - return - } - - if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil { - return - } - if err = os.Rename(tmpDir, runtimeDir); err != nil { - err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start") - return - } - if err = os.RemoveAll(runtimeDir + "-old"); err != nil { - logrus.WithError(err).WithField("dir", tmpDir). - Warn("failed to remove old runtimes dir") - } - }() - - for name, rt := range runtimes { - if len(rt.Args) == 0 { - continue - } - - script := filepath.Join(tmpDir, name) - content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " ")) - if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil { - return err - } - } - return nil -} - // verifyDaemonSettings performs validation of daemon config struct func verifyDaemonSettings(conf *config.Config) error { if conf.ContainerdNamespace == conf.ContainerdPluginNamespace { @@ -808,14 +759,15 @@ func verifyDaemonSettings(conf *config.Config) error { return fmt.Errorf("exec-opt native.cgroupdriver=systemd requires cgroup v2 for rootless mode") } - if conf.DefaultRuntime == "" { - conf.DefaultRuntime = config.StockRuntimeName + configureRuntimes(conf) + if rtName := conf.GetDefaultRuntimeName(); rtName != "" { + if conf.GetRuntime(rtName) == nil { + return fmt.Errorf("specified default runtime '%s' does not exist", rtName) + } + if rtName == config.LinuxV1RuntimeName { + logrus.Warnf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName) + } } - if conf.Runtimes == nil { - conf.Runtimes = make(map[string]types.Runtime) - } - conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeName} - return nil } @@ -1756,10 +1708,6 @@ func (daemon *Daemon) setupSeccompProfile() error { return nil } -func (daemon *Daemon) useShimV2() bool { - return cgroups.IsCgroup2UnifiedMode() -} - // RawSysInfo returns *sysinfo.SysInfo . func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo { var opts []sysinfo.Opt diff --git a/daemon/info.go b/daemon/info.go index 72f30cdd00..cbae94ec47 100644 --- a/daemon/info.go +++ b/daemon/info.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/api/types" "github.com/docker/docker/cli/debug" + "github.com/docker/docker/daemon/config" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/dockerversion" "github.com/docker/docker/pkg/fileutils" @@ -78,6 +79,10 @@ func (daemon *Daemon) SystemInfo() *types.Info { daemon.fillSecurityOptions(v, sysInfo) daemon.fillLicense(v) + if v.DefaultRuntime == config.LinuxV1RuntimeName { + v.Warnings = append(v.Warnings, fmt.Sprintf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName)) + } + return v } diff --git a/daemon/reload_unix.go b/daemon/reload_unix.go index 5d684fd2ed..02ae20a1cd 100644 --- a/daemon/reload_unix.go +++ b/daemon/reload_unix.go @@ -48,7 +48,7 @@ func (daemon *Daemon) reloadPlatform(conf *config.Config, attributes map[string] if runtimeList.Len() > 0 { runtimeList.WriteRune(' ') } - runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt)) + runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt.Path)) } attributes["runtimes"] = runtimeList.String() diff --git a/daemon/runtime_unix.go b/daemon/runtime_unix.go new file mode 100644 index 0000000000..17e2b15d49 --- /dev/null +++ b/daemon/runtime_unix.go @@ -0,0 +1,134 @@ +// +build !windows + +package daemon + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/containerd/containerd/runtime/linux/runctypes" + v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/docker/docker/api/types" + "github.com/docker/docker/daemon/config" + "github.com/docker/docker/pkg/ioutils" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + defaultRuntimeName = "runc" + + linuxShimV1 = "io.containerd.runtime.v1.linux" + linuxShimV2 = "io.containerd.runc.v2" +) + +func configureRuntimes(conf *config.Config) { + if conf.DefaultRuntime == "" { + conf.DefaultRuntime = config.StockRuntimeName + } + if conf.Runtimes == nil { + conf.Runtimes = make(map[string]types.Runtime) + } + conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: getShimConfig(conf, defaultRuntimeName)} + conf.Runtimes[config.LinuxV1RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV1ShimConfig(conf, defaultRuntimeName)} + conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)} +} + +func getShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig { + if cgroups.IsCgroup2UnifiedMode() { + return defaultV2ShimConfig(conf, runtimePath) + } + return defaultV1ShimConfig(conf, runtimePath) +} + +func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig { + return &types.ShimConfig{ + Binary: linuxShimV2, + Opts: &v2runcoptions.Options{ + BinaryName: runtimePath, + Root: filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName), + SystemdCgroup: UsingSystemd(conf), + NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "", + }, + } +} + +func defaultV1ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig { + return &types.ShimConfig{ + Binary: linuxShimV1, + Opts: &runctypes.RuncOptions{ + Runtime: runtimePath, + RuntimeRoot: filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName), + SystemdCgroup: UsingSystemd(conf), + }, + } +} + +func (daemon *Daemon) loadRuntimes() error { + return daemon.initRuntimes(daemon.configStore.Runtimes) +} + +func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) { + runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes") + // Remove old temp directory if any + os.RemoveAll(runtimeDir + "-old") + tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes") + if err != nil { + return errors.Wrap(err, "failed to get temp dir to generate runtime scripts") + } + defer func() { + if err != nil { + if err1 := os.RemoveAll(tmpDir); err1 != nil { + logrus.WithError(err1).WithField("dir", tmpDir). + Warn("failed to remove tmp dir") + } + return + } + + if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil { + return + } + if err = os.Rename(tmpDir, runtimeDir); err != nil { + err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start") + return + } + if err = os.RemoveAll(runtimeDir + "-old"); err != nil { + logrus.WithError(err).WithField("dir", tmpDir). + Warn("failed to remove old runtimes dir") + } + }() + + for name, rt := range runtimes { + if len(rt.Args) == 0 { + continue + } + + script := filepath.Join(tmpDir, name) + content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " ")) + if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil { + return err + } + } + return nil +} + +// rewriteRuntimePath is used for runtimes which have custom arguments supplied. +// This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments. +// To support this case, the daemon wraps the specified runtime in a script that passes through those arguments. +func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) { + if len(args) == 0 { + return p, nil + } + + // Check that the runtime path actually exists here so that we can return a well known error. + if _, err := exec.LookPath(p); err != nil { + return "", errors.Wrap(err, "error while looking up the specified runtime path") + } + + return filepath.Join(daemon.configStore.Root, "runtimes", name), nil +} diff --git a/daemon/start.go b/daemon/start.go index 857b5fb80b..6126efacbf 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -175,7 +175,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint } } - createOptions, err := daemon.getLibcontainerdCreateOptions(container) + shim, createOptions, err := daemon.getLibcontainerdCreateOptions(container) if err != nil { return err } @@ -187,7 +187,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint return err } - err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String())) + err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String())) if err != nil { if errdefs.IsConflict(err) { logrus.WithError(err).WithField("container", container.ID).Error("Container not cleaned up from containerd from previous run") @@ -196,7 +196,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint if err := daemon.containerd.Delete(ctx, container.ID); err != nil && !errdefs.IsNotFound(err) { logrus.WithError(err).WithField("container", container.ID).Error("Error cleaning up stale containerd container object") } - err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String())) + err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String())) } if err != nil { return translateContainerdStartErr(container.Path, container.SetExitCode, err) diff --git a/daemon/start_unix.go b/daemon/start_unix.go index 73963b9cf6..4373a97d83 100644 --- a/daemon/start_unix.go +++ b/daemon/start_unix.go @@ -3,70 +3,35 @@ package daemon // import "github.com/docker/docker/daemon" import ( - "fmt" - "os/exec" - "path/filepath" - - "github.com/containerd/containerd/runtime/linux/runctypes" - v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/docker/docker/container" "github.com/docker/docker/errdefs" + "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) -func (daemon *Daemon) getRuntimeScript(container *container.Container) (string, error) { - name := container.HostConfig.Runtime - rt := daemon.configStore.GetRuntime(name) - if rt == nil { - return "", errdefs.InvalidParameter(errors.Errorf("no such runtime '%s'", name)) - } - - if len(rt.Args) > 0 { - // First check that the target exist, as using it in a script won't - // give us the right error - if _, err := exec.LookPath(rt.Path); err != nil { - return "", translateContainerdStartErr(container.Path, container.SetExitCode, err) - } - return filepath.Join(daemon.configStore.Root, "runtimes", name), nil - } - return rt.Path, nil -} - // getLibcontainerdCreateOptions callers must hold a lock on the container -func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) { +func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) { // Ensure a runtime has been assigned to this container if container.HostConfig.Runtime == "" { container.HostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName() container.CheckpointTo(daemon.containersReplica) } - path, err := daemon.getRuntimeScript(container) - if err != nil { - return nil, err - } - if daemon.useShimV2() { - opts := &v2runcoptions.Options{ - BinaryName: path, - Root: filepath.Join(daemon.configStore.ExecRoot, - fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)), + rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime) + if rt.Shim == nil { + p, err := daemon.rewriteRuntimePath(container.HostConfig.Runtime, rt.Path, rt.Args) + if err != nil { + return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err) } - - if UsingSystemd(daemon.configStore) { - opts.SystemdCgroup = true + rt.Shim = getShimConfig(daemon.configStore, p) + } + if rt.Shim.Binary == linuxShimV1 { + if cgroups.IsCgroup2UnifiedMode() { + return "", nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", container.HostConfig.Runtime)) } - - return opts, nil - - } - opts := &runctypes.RuncOptions{ - Runtime: path, - RuntimeRoot: filepath.Join(daemon.configStore.ExecRoot, - fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)), + logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", container.HostConfig.Runtime) } - if UsingSystemd(daemon.configStore) { - opts.SystemdCgroup = true - } - - return opts, nil + return rt.Shim.Binary, rt.Shim.Opts, nil } diff --git a/daemon/start_windows.go b/daemon/start_windows.go index fc34375e7e..d21fec5d70 100644 --- a/daemon/start_windows.go +++ b/daemon/start_windows.go @@ -7,12 +7,12 @@ import ( "github.com/docker/docker/pkg/system" ) -func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) { +func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) { // Set the runtime options to debug regardless of current logging level. if system.ContainerdRuntimeSupported() { opts := &options.Options{Debug: true} - return opts, nil + return "", opts, nil } // TODO (containerd) - Probably need to revisit LCOW options here @@ -22,7 +22,7 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain if container.OS == "linux" { config := &client.Config{} if err := config.GenerateDefault(daemon.configStore.GraphOptions); err != nil { - return nil, err + return "", nil, err } // Override from user-supplied options. for k, v := range container.HostConfig.StorageOpt { @@ -34,11 +34,11 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain } } if err := config.Validate(); err != nil { - return nil, err + return "", nil, err } - return config, nil + return "", config, nil } - return nil, nil + return "", nil, nil } diff --git a/daemon/util_test.go b/daemon/util_test.go index 6ef9ba682b..05cf1dd344 100644 --- a/daemon/util_test.go +++ b/daemon/util_test.go @@ -28,7 +28,7 @@ func (c *MockContainerdClient) Version(ctx context.Context) (containerd.Version, func (c *MockContainerdClient) Restore(ctx context.Context, containerID string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, p libcontainerdtypes.Process, err error) { return false, 0, &mockProcess{}, nil } -func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { +func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { return nil } func (c *MockContainerdClient) Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error) { diff --git a/libcontainerd/libcontainerd_linux.go b/libcontainerd/libcontainerd_linux.go index 3b008fe256..ec195a7905 100644 --- a/libcontainerd/libcontainerd_linux.go +++ b/libcontainerd/libcontainerd_linux.go @@ -9,6 +9,6 @@ import ( ) // NewClient creates a new libcontainerd client from a containerd client -func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) { - return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2) +func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) { + return remote.NewClient(ctx, cli, stateDir, ns, b) } diff --git a/libcontainerd/libcontainerd_windows.go b/libcontainerd/libcontainerd_windows.go index 5a64180be4..e7f0bc9d30 100644 --- a/libcontainerd/libcontainerd_windows.go +++ b/libcontainerd/libcontainerd_windows.go @@ -11,10 +11,10 @@ import ( ) // NewClient creates a new libcontainerd client from a containerd client -func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) { +func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) { if !system.ContainerdRuntimeSupported() { // useShimV2 is ignored for windows return local.NewClient(ctx, cli, stateDir, ns, b) } - return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2) + return remote.NewClient(ctx, cli, stateDir, ns, b) } diff --git a/libcontainerd/local/local_windows.go b/libcontainerd/local/local_windows.go index 67592e54e8..85e1d8c772 100644 --- a/libcontainerd/local/local_windows.go +++ b/libcontainerd/local/local_windows.go @@ -153,7 +153,7 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) { // "ImagePath": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c\\\\UtilityVM" // }, // } -func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { +func (c *client) Create(_ context.Context, id string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { if ctr := c.getContainer(id); ctr != nil { return errors.WithStack(errdefs.Conflict(errors.New("id already in use"))) } diff --git a/libcontainerd/remote/client.go b/libcontainerd/remote/client.go index 9bc4ffde02..11a5990a7b 100644 --- a/libcontainerd/remote/client.go +++ b/libcontainerd/remote/client.go @@ -50,14 +50,13 @@ type client struct { eventQ queue.Queue oomMu sync.Mutex oom map[string]bool - useShimV2 bool v2runcoptionsMu sync.Mutex // v2runcoptions is used for copying options specified on Create() to Start() v2runcoptions map[string]v2runcoptions.Options } // NewClient creates a new libcontainerd client from a containerd client -func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) { +func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) { c := &client{ client: cli, stateDir: stateDir, @@ -65,7 +64,6 @@ func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, ns: ns, backend: b, oom: make(map[string]bool), - useShimV2: useShimV2, v2runcoptions: make(map[string]v2runcoptions.Options), } @@ -129,17 +127,13 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio libcontaine }, nil } -func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { +func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error { bdir := c.bundleDir(id) c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created") - rt := runtimeName - if c.useShimV2 { - rt = shimV2RuntimeName - } newOpts := []containerd.NewContainerOpts{ containerd.WithSpec(ociSpec), - containerd.WithRuntime(rt, runtimeOptions), + containerd.WithRuntime(shim, runtimeOptions), WithBundle(bdir, ociSpec), } opts = append(opts, newOpts...) @@ -151,12 +145,10 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run } return wrapError(err) } - if c.useShimV2 { - if x, ok := runtimeOptions.(*v2runcoptions.Options); ok { - c.v2runcoptionsMu.Lock() - c.v2runcoptions[id] = *x - c.v2runcoptionsMu.Unlock() - } + if x, ok := runtimeOptions.(*v2runcoptions.Options); ok { + c.v2runcoptionsMu.Lock() + c.v2runcoptions[id] = *x + c.v2runcoptionsMu.Unlock() } return nil } @@ -218,17 +210,12 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin if runtime.GOOS != "windows" { taskOpts = append(taskOpts, func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error { - if c.useShimV2 { - // For v2, we need to inherit options specified on Create - c.v2runcoptionsMu.Lock() - opts, ok := c.v2runcoptions[id] - c.v2runcoptionsMu.Unlock() - if !ok { - opts = v2runcoptions.Options{} - } + c.v2runcoptionsMu.Lock() + opts, ok := c.v2runcoptions[id] + c.v2runcoptionsMu.Unlock() + if ok { opts.IoUid = uint32(uid) opts.IoGid = uint32(gid) - opts.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != "" info.Options = &opts } else { info.Options = &runctypes.CreateOptions{ @@ -237,7 +224,6 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "", } } - return nil }) } else { diff --git a/libcontainerd/remote/client_linux.go b/libcontainerd/remote/client_linux.go index 637ac94d82..e45d140b2f 100644 --- a/libcontainerd/remote/client_linux.go +++ b/libcontainerd/remote/client_linux.go @@ -16,11 +16,6 @@ import ( "github.com/sirupsen/logrus" ) -const ( - runtimeName = "io.containerd.runtime.v1.linux" - shimV2RuntimeName = "io.containerd.runc.v2" -) - func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) { return &libcontainerdtypes.Summary{}, nil } diff --git a/libcontainerd/types/types.go b/libcontainerd/types/types.go index ba88e4db6f..1d1a420e79 100644 --- a/libcontainerd/types/types.go +++ b/libcontainerd/types/types.go @@ -52,7 +52,7 @@ type Client interface { Restore(ctx context.Context, containerID string, attachStdio StdioCallback) (alive bool, pid int, p Process, err error) - Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error + Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio StdioCallback) (pid int, err error) SignalProcess(ctx context.Context, containerID, processID string, signal int) error Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error) diff --git a/plugin/executor/containerd/containerd.go b/plugin/executor/containerd/containerd.go index aeeb2184ec..8354745990 100644 --- a/plugin/executor/containerd/containerd.go +++ b/plugin/executor/containerd/containerd.go @@ -3,12 +3,11 @@ package containerd // import "github.com/docker/docker/plugin/executor/container import ( "context" "io" - "path/filepath" "sync" "github.com/containerd/containerd" "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/runtime/linux/runctypes" + "github.com/docker/docker/api/types" "github.com/docker/docker/errdefs" "github.com/docker/docker/libcontainerd" libcontainerdtypes "github.com/docker/docker/libcontainerd/types" @@ -26,13 +25,14 @@ type ExitHandler interface { } // New creates a new containerd plugin executor -func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, useShimV2 bool) (*Executor, error) { +func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, runtime types.Runtime) (*Executor, error) { e := &Executor{ rootDir: rootDir, exitHandler: exitHandler, + runtime: runtime, } - client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e, useShimV2) + client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e) if err != nil { return nil, errors.Wrap(err, "error creating containerd exec client") } @@ -45,6 +45,7 @@ type Executor struct { rootDir string client libcontainerdtypes.Client exitHandler ExitHandler + runtime types.Runtime } // deleteTaskAndContainer deletes plugin task and then plugin container from containerd @@ -66,11 +67,8 @@ func deleteTaskAndContainer(ctx context.Context, cli libcontainerdtypes.Client, // Create creates a new container func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteCloser) error { - opts := runctypes.RuncOptions{ - RuntimeRoot: filepath.Join(e.rootDir, "runtime-root"), - } ctx := context.Background() - err := e.client.Create(ctx, id, &spec, &opts) + err := e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts) if err != nil { status, err2 := e.client.Status(ctx, id) if err2 != nil { @@ -82,7 +80,7 @@ func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteClo if err2 := e.client.Delete(ctx, id); err2 != nil && !errdefs.IsNotFound(err2) { logrus.WithError(err2).WithField("plugin", id).Error("Error cleaning up containerd container") } - err = e.client.Create(ctx, id, &spec, &opts) + err = e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts) } }