Browse code

Configure shims from runtime config

In dockerd we already have a concept of a "runtime", which specifies the
OCI runtime to use (e.g. runc).
This PR extends that config to add containerd shim configuration.
This option is only exposed within the daemon itself (cannot be
configured in daemon.json).
This is due to issues in supporting unknown shims which will require
more design work.

What this change allows us to do is keep all the runtime config in one
place.

So the default "runc" runtime will just have it's already existing shim
config codified within the runtime config alone.
I've also added 2 more "stock" runtimes which are basically runc+shimv1
and runc+shimv2.
These new runtime configurations are:

- io.containerd.runtime.v1.linux - runc + v1 shim using the V1 shim API
- io.containerd.runc.v2 - runc + shim v2

These names coincide with the actual names of the containerd shims.

This allows the user to essentially control what shim is going to be
used by either specifying these as a `--runtime` on container create or
by setting `--default-runtime` on the daemon.

For custom/user-specified runtimes, the default shim config (currently
shim v1) is used.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2020/07/08 05:33:46
Showing 17 changed files
... ...
@@ -511,6 +511,16 @@ type Checkpoint struct {
511 511
 type Runtime struct {
512 512
 	Path string   `json:"path"`
513 513
 	Args []string `json:"runtimeArgs,omitempty"`
514
+
515
+	// This is exposed here only for internal use
516
+	// It is not currently supported to specify custom shim configs
517
+	Shim *ShimConfig `json:"-"`
518
+}
519
+
520
+// ShimConfig is used by runtime to configure containerd shims
521
+type ShimConfig struct {
522
+	Binary string
523
+	Opts   interface{}
514 524
 }
515 525
 
516 526
 // DiskUsage contains response of Engine API:
... ...
@@ -36,9 +36,6 @@ const (
36 36
 	// maximum number of attempts that
37 37
 	// may take place at a time for each pull when the connection is lost.
38 38
 	DefaultDownloadAttempts = 5
39
-	// StockRuntimeName is the reserved name/alias used to represent the
40
-	// OCI runtime being shipped with the docker daemon package.
41
-	StockRuntimeName = "runc"
42 39
 	// DefaultShmSize is the default value for container's shm size
43 40
 	DefaultShmSize = int64(67108864)
44 41
 	// DefaultNetworkMtu is the default value for network MTU
... ...
@@ -47,8 +44,24 @@ const (
47 47
 	DisableNetworkBridge = "none"
48 48
 	// DefaultInitBinary is the name of the default init binary
49 49
 	DefaultInitBinary = "docker-init"
50
+
51
+	// StockRuntimeName is the reserved name/alias used to represent the
52
+	// OCI runtime being shipped with the docker daemon package.
53
+	StockRuntimeName = "runc"
54
+	// LinuxV1RuntimeName is the runtime used to specify the containerd v1 shim with the runc binary
55
+	// Note this is different than io.containerd.runc.v1 which would be the v1 shim using the v2 shim API.
56
+	// This is specifically for the v1 shim using the v1 shim API.
57
+	LinuxV1RuntimeName = "io.containerd.runtime.v1.linux"
58
+	// LinuxV2RuntimeName is the runtime used to specify the containerd v2 runc shim
59
+	LinuxV2RuntimeName = "io.containerd.runc.v2"
50 60
 )
51 61
 
62
+var builtinRuntimes = map[string]bool{
63
+	StockRuntimeName:   true,
64
+	LinuxV1RuntimeName: true,
65
+	LinuxV2RuntimeName: true,
66
+}
67
+
52 68
 // flatOptions contains configuration keys
53 69
 // that MUST NOT be parsed as deep structures.
54 70
 // Use this to differentiate these options
... ...
@@ -571,10 +584,12 @@ func Validate(config *Config) error {
571 571
 		return err
572 572
 	}
573 573
 
574
-	if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != StockRuntimeName {
575
-		runtimes := config.GetAllRuntimes()
576
-		if _, ok := runtimes[defaultRuntime]; !ok {
577
-			return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime)
574
+	if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" {
575
+		if !builtinRuntimes[defaultRuntime] {
576
+			runtimes := config.GetAllRuntimes()
577
+			if _, ok := runtimes[defaultRuntime]; !ok {
578
+				return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime)
579
+			}
578 580
 		}
579 581
 	}
580 582
 
... ...
@@ -932,7 +932,11 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
932 932
 			}
933 933
 		}
934 934
 
935
-		return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, d.useShimV2())
935
+		var rt types.Runtime
936
+		if runtime := config.GetRuntime(config.GetDefaultRuntimeName()); runtime != nil {
937
+			rt = *runtime
938
+		}
939
+		return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, rt)
936 940
 	}
937 941
 
938 942
 	// 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
1081 1081
 
1082 1082
 	go d.execCommandGC()
1083 1083
 
1084
-	d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d, d.useShimV2())
1084
+	d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d)
1085 1085
 	if err != nil {
1086 1086
 		return nil, err
1087 1087
 	}
... ...
@@ -30,7 +30,6 @@ import (
30 30
 	"github.com/docker/docker/opts"
31 31
 	"github.com/docker/docker/pkg/containerfs"
32 32
 	"github.com/docker/docker/pkg/idtools"
33
-	"github.com/docker/docker/pkg/ioutils"
34 33
 	"github.com/docker/docker/pkg/parsers"
35 34
 	"github.com/docker/docker/pkg/parsers/kernel"
36 35
 	"github.com/docker/docker/pkg/sysinfo"
... ...
@@ -78,10 +77,6 @@ const (
78 78
 	cgroupFsDriver      = "cgroupfs"
79 79
 	cgroupSystemdDriver = "systemd"
80 80
 	cgroupNoneDriver    = "none"
81
-
82
-	// DefaultRuntimeName is the default runtime to be used by
83
-	// containerd if none is specified
84
-	DefaultRuntimeName = "runc"
85 81
 )
86 82
 
87 83
 type containerGetter interface {
... ...
@@ -729,55 +724,11 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
729 729
 		}
730 730
 	}
731 731
 
732
-	return warnings, nil
733
-}
734
-
735
-func (daemon *Daemon) loadRuntimes() error {
736
-	return daemon.initRuntimes(daemon.configStore.Runtimes)
737
-}
738
-
739
-func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
740
-	runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
741
-	// Remove old temp directory if any
742
-	os.RemoveAll(runtimeDir + "-old")
743
-	tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes")
744
-	if err != nil {
745
-		return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
732
+	if hostConfig.Runtime == config.LinuxV1RuntimeName || (hostConfig.Runtime == "" && daemon.configStore.DefaultRuntime == config.LinuxV1RuntimeName) {
733
+		warnings = append(warnings, fmt.Sprintf("Configured runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName))
746 734
 	}
747
-	defer func() {
748
-		if err != nil {
749
-			if err1 := os.RemoveAll(tmpDir); err1 != nil {
750
-				logrus.WithError(err1).WithField("dir", tmpDir).
751
-					Warn("failed to remove tmp dir")
752
-			}
753
-			return
754
-		}
755
-
756
-		if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil {
757
-			return
758
-		}
759
-		if err = os.Rename(tmpDir, runtimeDir); err != nil {
760
-			err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
761
-			return
762
-		}
763
-		if err = os.RemoveAll(runtimeDir + "-old"); err != nil {
764
-			logrus.WithError(err).WithField("dir", tmpDir).
765
-				Warn("failed to remove old runtimes dir")
766
-		}
767
-	}()
768 735
 
769
-	for name, rt := range runtimes {
770
-		if len(rt.Args) == 0 {
771
-			continue
772
-		}
773
-
774
-		script := filepath.Join(tmpDir, name)
775
-		content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
776
-		if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
777
-			return err
778
-		}
779
-	}
780
-	return nil
736
+	return warnings, nil
781 737
 }
782 738
 
783 739
 // verifyDaemonSettings performs validation of daemon config struct
... ...
@@ -808,14 +759,15 @@ func verifyDaemonSettings(conf *config.Config) error {
808 808
 		return fmt.Errorf("exec-opt native.cgroupdriver=systemd requires cgroup v2 for rootless mode")
809 809
 	}
810 810
 
811
-	if conf.DefaultRuntime == "" {
812
-		conf.DefaultRuntime = config.StockRuntimeName
813
-	}
814
-	if conf.Runtimes == nil {
815
-		conf.Runtimes = make(map[string]types.Runtime)
811
+	configureRuntimes(conf)
812
+	if rtName := conf.GetDefaultRuntimeName(); rtName != "" {
813
+		if conf.GetRuntime(rtName) == nil {
814
+			return fmt.Errorf("specified default runtime '%s' does not exist", rtName)
815
+		}
816
+		if rtName == config.LinuxV1RuntimeName {
817
+			logrus.Warnf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName)
818
+		}
816 819
 	}
817
-	conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeName}
818
-
819 820
 	return nil
820 821
 }
821 822
 
... ...
@@ -1756,10 +1708,6 @@ func (daemon *Daemon) setupSeccompProfile() error {
1756 1756
 	return nil
1757 1757
 }
1758 1758
 
1759
-func (daemon *Daemon) useShimV2() bool {
1760
-	return cgroups.IsCgroup2UnifiedMode()
1761
-}
1762
-
1763 1759
 // RawSysInfo returns *sysinfo.SysInfo .
1764 1760
 func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo {
1765 1761
 	var opts []sysinfo.Opt
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/docker/docker/api"
12 12
 	"github.com/docker/docker/api/types"
13 13
 	"github.com/docker/docker/cli/debug"
14
+	"github.com/docker/docker/daemon/config"
14 15
 	"github.com/docker/docker/daemon/logger"
15 16
 	"github.com/docker/docker/dockerversion"
16 17
 	"github.com/docker/docker/pkg/fileutils"
... ...
@@ -78,6 +79,10 @@ func (daemon *Daemon) SystemInfo() *types.Info {
78 78
 	daemon.fillSecurityOptions(v, sysInfo)
79 79
 	daemon.fillLicense(v)
80 80
 
81
+	if v.DefaultRuntime == config.LinuxV1RuntimeName {
82
+		v.Warnings = append(v.Warnings, fmt.Sprintf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName))
83
+	}
84
+
81 85
 	return v
82 86
 }
83 87
 
84 88
new file mode 100644
... ...
@@ -0,0 +1,134 @@
0
+// +build !windows
1
+
2
+package daemon
3
+
4
+import (
5
+	"fmt"
6
+	"io/ioutil"
7
+	"os"
8
+	"os/exec"
9
+	"path/filepath"
10
+	"strings"
11
+
12
+	"github.com/containerd/containerd/runtime/linux/runctypes"
13
+	v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
14
+	"github.com/docker/docker/api/types"
15
+	"github.com/docker/docker/daemon/config"
16
+	"github.com/docker/docker/pkg/ioutils"
17
+	"github.com/opencontainers/runc/libcontainer/cgroups"
18
+	"github.com/pkg/errors"
19
+	"github.com/sirupsen/logrus"
20
+)
21
+
22
+const (
23
+	defaultRuntimeName = "runc"
24
+
25
+	linuxShimV1 = "io.containerd.runtime.v1.linux"
26
+	linuxShimV2 = "io.containerd.runc.v2"
27
+)
28
+
29
+func configureRuntimes(conf *config.Config) {
30
+	if conf.DefaultRuntime == "" {
31
+		conf.DefaultRuntime = config.StockRuntimeName
32
+	}
33
+	if conf.Runtimes == nil {
34
+		conf.Runtimes = make(map[string]types.Runtime)
35
+	}
36
+	conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: getShimConfig(conf, defaultRuntimeName)}
37
+	conf.Runtimes[config.LinuxV1RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV1ShimConfig(conf, defaultRuntimeName)}
38
+	conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)}
39
+}
40
+
41
+func getShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
42
+	if cgroups.IsCgroup2UnifiedMode() {
43
+		return defaultV2ShimConfig(conf, runtimePath)
44
+	}
45
+	return defaultV1ShimConfig(conf, runtimePath)
46
+}
47
+
48
+func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
49
+	return &types.ShimConfig{
50
+		Binary: linuxShimV2,
51
+		Opts: &v2runcoptions.Options{
52
+			BinaryName:    runtimePath,
53
+			Root:          filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
54
+			SystemdCgroup: UsingSystemd(conf),
55
+			NoPivotRoot:   os.Getenv("DOCKER_RAMDISK") != "",
56
+		},
57
+	}
58
+}
59
+
60
+func defaultV1ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
61
+	return &types.ShimConfig{
62
+		Binary: linuxShimV1,
63
+		Opts: &runctypes.RuncOptions{
64
+			Runtime:       runtimePath,
65
+			RuntimeRoot:   filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
66
+			SystemdCgroup: UsingSystemd(conf),
67
+		},
68
+	}
69
+}
70
+
71
+func (daemon *Daemon) loadRuntimes() error {
72
+	return daemon.initRuntimes(daemon.configStore.Runtimes)
73
+}
74
+
75
+func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
76
+	runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
77
+	// Remove old temp directory if any
78
+	os.RemoveAll(runtimeDir + "-old")
79
+	tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes")
80
+	if err != nil {
81
+		return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
82
+	}
83
+	defer func() {
84
+		if err != nil {
85
+			if err1 := os.RemoveAll(tmpDir); err1 != nil {
86
+				logrus.WithError(err1).WithField("dir", tmpDir).
87
+					Warn("failed to remove tmp dir")
88
+			}
89
+			return
90
+		}
91
+
92
+		if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil {
93
+			return
94
+		}
95
+		if err = os.Rename(tmpDir, runtimeDir); err != nil {
96
+			err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
97
+			return
98
+		}
99
+		if err = os.RemoveAll(runtimeDir + "-old"); err != nil {
100
+			logrus.WithError(err).WithField("dir", tmpDir).
101
+				Warn("failed to remove old runtimes dir")
102
+		}
103
+	}()
104
+
105
+	for name, rt := range runtimes {
106
+		if len(rt.Args) == 0 {
107
+			continue
108
+		}
109
+
110
+		script := filepath.Join(tmpDir, name)
111
+		content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
112
+		if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
113
+			return err
114
+		}
115
+	}
116
+	return nil
117
+}
118
+
119
+// rewriteRuntimePath is used for runtimes which have custom arguments supplied.
120
+// This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments.
121
+// To support this case, the daemon wraps the specified runtime in a script that passes through those arguments.
122
+func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) {
123
+	if len(args) == 0 {
124
+		return p, nil
125
+	}
126
+
127
+	// Check that the runtime path actually exists here so that we can return a well known error.
128
+	if _, err := exec.LookPath(p); err != nil {
129
+		return "", errors.Wrap(err, "error while looking up the specified runtime path")
130
+	}
131
+
132
+	return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
133
+}
... ...
@@ -175,7 +175,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
175 175
 		}
176 176
 	}
177 177
 
178
-	createOptions, err := daemon.getLibcontainerdCreateOptions(container)
178
+	shim, createOptions, err := daemon.getLibcontainerdCreateOptions(container)
179 179
 	if err != nil {
180 180
 		return err
181 181
 	}
... ...
@@ -187,7 +187,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
187 187
 		return err
188 188
 	}
189 189
 
190
-	err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String()))
190
+	err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String()))
191 191
 	if err != nil {
192 192
 		if errdefs.IsConflict(err) {
193 193
 			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
196 196
 			if err := daemon.containerd.Delete(ctx, container.ID); err != nil && !errdefs.IsNotFound(err) {
197 197
 				logrus.WithError(err).WithField("container", container.ID).Error("Error cleaning up stale containerd container object")
198 198
 			}
199
-			err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String()))
199
+			err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String()))
200 200
 		}
201 201
 		if err != nil {
202 202
 			return translateContainerdStartErr(container.Path, container.SetExitCode, err)
... ...
@@ -3,70 +3,35 @@
3 3
 package daemon // import "github.com/docker/docker/daemon"
4 4
 
5 5
 import (
6
-	"fmt"
7
-	"os/exec"
8
-	"path/filepath"
9
-
10
-	"github.com/containerd/containerd/runtime/linux/runctypes"
11
-	v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
12 6
 	"github.com/docker/docker/container"
13 7
 	"github.com/docker/docker/errdefs"
8
+	"github.com/opencontainers/runc/libcontainer/cgroups"
14 9
 	"github.com/pkg/errors"
10
+	"github.com/sirupsen/logrus"
15 11
 )
16 12
 
17
-func (daemon *Daemon) getRuntimeScript(container *container.Container) (string, error) {
18
-	name := container.HostConfig.Runtime
19
-	rt := daemon.configStore.GetRuntime(name)
20
-	if rt == nil {
21
-		return "", errdefs.InvalidParameter(errors.Errorf("no such runtime '%s'", name))
22
-	}
23
-
24
-	if len(rt.Args) > 0 {
25
-		// First check that the target exist, as using it in a script won't
26
-		// give us the right error
27
-		if _, err := exec.LookPath(rt.Path); err != nil {
28
-			return "", translateContainerdStartErr(container.Path, container.SetExitCode, err)
29
-		}
30
-		return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
31
-	}
32
-	return rt.Path, nil
33
-}
34
-
35 13
 // getLibcontainerdCreateOptions callers must hold a lock on the container
36
-func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) {
14
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) {
37 15
 	// Ensure a runtime has been assigned to this container
38 16
 	if container.HostConfig.Runtime == "" {
39 17
 		container.HostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
40 18
 		container.CheckpointTo(daemon.containersReplica)
41 19
 	}
42 20
 
43
-	path, err := daemon.getRuntimeScript(container)
44
-	if err != nil {
45
-		return nil, err
46
-	}
47
-	if daemon.useShimV2() {
48
-		opts := &v2runcoptions.Options{
49
-			BinaryName: path,
50
-			Root: filepath.Join(daemon.configStore.ExecRoot,
51
-				fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)),
21
+	rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime)
22
+	if rt.Shim == nil {
23
+		p, err := daemon.rewriteRuntimePath(container.HostConfig.Runtime, rt.Path, rt.Args)
24
+		if err != nil {
25
+			return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err)
52 26
 		}
53
-
54
-		if UsingSystemd(daemon.configStore) {
55
-			opts.SystemdCgroup = true
56
-		}
57
-
58
-		return opts, nil
59
-
27
+		rt.Shim = getShimConfig(daemon.configStore, p)
60 28
 	}
61
-	opts := &runctypes.RuncOptions{
62
-		Runtime: path,
63
-		RuntimeRoot: filepath.Join(daemon.configStore.ExecRoot,
64
-			fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)),
65
-	}
66
-
67
-	if UsingSystemd(daemon.configStore) {
68
-		opts.SystemdCgroup = true
29
+	if rt.Shim.Binary == linuxShimV1 {
30
+		if cgroups.IsCgroup2UnifiedMode() {
31
+			return "", nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", container.HostConfig.Runtime))
32
+		}
33
+		logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", container.HostConfig.Runtime)
69 34
 	}
70 35
 
71
-	return opts, nil
36
+	return rt.Shim.Binary, rt.Shim.Opts, nil
72 37
 }
... ...
@@ -7,12 +7,12 @@ import (
7 7
 	"github.com/docker/docker/pkg/system"
8 8
 )
9 9
 
10
-func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) {
10
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) {
11 11
 
12 12
 	// Set the runtime options to debug regardless of current logging level.
13 13
 	if system.ContainerdRuntimeSupported() {
14 14
 		opts := &options.Options{Debug: true}
15
-		return opts, nil
15
+		return "", opts, nil
16 16
 	}
17 17
 
18 18
 	// TODO (containerd) - Probably need to revisit LCOW options here
... ...
@@ -22,7 +22,7 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
22 22
 	if container.OS == "linux" {
23 23
 		config := &client.Config{}
24 24
 		if err := config.GenerateDefault(daemon.configStore.GraphOptions); err != nil {
25
-			return nil, err
25
+			return "", nil, err
26 26
 		}
27 27
 		// Override from user-supplied options.
28 28
 		for k, v := range container.HostConfig.StorageOpt {
... ...
@@ -34,11 +34,11 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
34 34
 			}
35 35
 		}
36 36
 		if err := config.Validate(); err != nil {
37
-			return nil, err
37
+			return "", nil, err
38 38
 		}
39 39
 
40
-		return config, nil
40
+		return "", config, nil
41 41
 	}
42 42
 
43
-	return nil, nil
43
+	return "", nil, nil
44 44
 }
... ...
@@ -28,7 +28,7 @@ func (c *MockContainerdClient) Version(ctx context.Context) (containerd.Version,
28 28
 func (c *MockContainerdClient) Restore(ctx context.Context, containerID string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, p libcontainerdtypes.Process, err error) {
29 29
 	return false, 0, &mockProcess{}, nil
30 30
 }
31
-func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
31
+func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
32 32
 	return nil
33 33
 }
34 34
 func (c *MockContainerdClient) Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error) {
... ...
@@ -9,6 +9,6 @@ import (
9 9
 )
10 10
 
11 11
 // NewClient creates a new libcontainerd client from a containerd client
12
-func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
13
-	return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2)
12
+func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
13
+	return remote.NewClient(ctx, cli, stateDir, ns, b)
14 14
 }
... ...
@@ -11,10 +11,10 @@ import (
11 11
 )
12 12
 
13 13
 // NewClient creates a new libcontainerd client from a containerd client
14
-func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
14
+func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
15 15
 	if !system.ContainerdRuntimeSupported() {
16 16
 		// useShimV2 is ignored for windows
17 17
 		return local.NewClient(ctx, cli, stateDir, ns, b)
18 18
 	}
19
-	return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2)
19
+	return remote.NewClient(ctx, cli, stateDir, ns, b)
20 20
 }
... ...
@@ -153,7 +153,7 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) {
153 153
 // 		"ImagePath": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c\\\\UtilityVM"
154 154
 // 	},
155 155
 // }
156
-func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
156
+func (c *client) Create(_ context.Context, id string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
157 157
 	if ctr := c.getContainer(id); ctr != nil {
158 158
 		return errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
159 159
 	}
... ...
@@ -50,14 +50,13 @@ type client struct {
50 50
 	eventQ          queue.Queue
51 51
 	oomMu           sync.Mutex
52 52
 	oom             map[string]bool
53
-	useShimV2       bool
54 53
 	v2runcoptionsMu sync.Mutex
55 54
 	// v2runcoptions is used for copying options specified on Create() to Start()
56 55
 	v2runcoptions map[string]v2runcoptions.Options
57 56
 }
58 57
 
59 58
 // NewClient creates a new libcontainerd client from a containerd client
60
-func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
59
+func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
61 60
 	c := &client{
62 61
 		client:        cli,
63 62
 		stateDir:      stateDir,
... ...
@@ -65,7 +64,6 @@ func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string,
65 65
 		ns:            ns,
66 66
 		backend:       b,
67 67
 		oom:           make(map[string]bool),
68
-		useShimV2:     useShimV2,
69 68
 		v2runcoptions: make(map[string]v2runcoptions.Options),
70 69
 	}
71 70
 
... ...
@@ -129,17 +127,13 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio libcontaine
129 129
 	}, nil
130 130
 }
131 131
 
132
-func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
132
+func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
133 133
 	bdir := c.bundleDir(id)
134 134
 	c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created")
135 135
 
136
-	rt := runtimeName
137
-	if c.useShimV2 {
138
-		rt = shimV2RuntimeName
139
-	}
140 136
 	newOpts := []containerd.NewContainerOpts{
141 137
 		containerd.WithSpec(ociSpec),
142
-		containerd.WithRuntime(rt, runtimeOptions),
138
+		containerd.WithRuntime(shim, runtimeOptions),
143 139
 		WithBundle(bdir, ociSpec),
144 140
 	}
145 141
 	opts = append(opts, newOpts...)
... ...
@@ -151,12 +145,10 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run
151 151
 		}
152 152
 		return wrapError(err)
153 153
 	}
154
-	if c.useShimV2 {
155
-		if x, ok := runtimeOptions.(*v2runcoptions.Options); ok {
156
-			c.v2runcoptionsMu.Lock()
157
-			c.v2runcoptions[id] = *x
158
-			c.v2runcoptionsMu.Unlock()
159
-		}
154
+	if x, ok := runtimeOptions.(*v2runcoptions.Options); ok {
155
+		c.v2runcoptionsMu.Lock()
156
+		c.v2runcoptions[id] = *x
157
+		c.v2runcoptionsMu.Unlock()
160 158
 	}
161 159
 	return nil
162 160
 }
... ...
@@ -218,17 +210,12 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
218 218
 
219 219
 	if runtime.GOOS != "windows" {
220 220
 		taskOpts = append(taskOpts, func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
221
-			if c.useShimV2 {
222
-				// For v2, we need to inherit options specified on Create
223
-				c.v2runcoptionsMu.Lock()
224
-				opts, ok := c.v2runcoptions[id]
225
-				c.v2runcoptionsMu.Unlock()
226
-				if !ok {
227
-					opts = v2runcoptions.Options{}
228
-				}
221
+			c.v2runcoptionsMu.Lock()
222
+			opts, ok := c.v2runcoptions[id]
223
+			c.v2runcoptionsMu.Unlock()
224
+			if ok {
229 225
 				opts.IoUid = uint32(uid)
230 226
 				opts.IoGid = uint32(gid)
231
-				opts.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
232 227
 				info.Options = &opts
233 228
 			} else {
234 229
 				info.Options = &runctypes.CreateOptions{
... ...
@@ -237,7 +224,6 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
237 237
 					NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
238 238
 				}
239 239
 			}
240
-
241 240
 			return nil
242 241
 		})
243 242
 	} else {
... ...
@@ -16,11 +16,6 @@ import (
16 16
 	"github.com/sirupsen/logrus"
17 17
 )
18 18
 
19
-const (
20
-	runtimeName       = "io.containerd.runtime.v1.linux"
21
-	shimV2RuntimeName = "io.containerd.runc.v2"
22
-)
23
-
24 19
 func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
25 20
 	return &libcontainerdtypes.Summary{}, nil
26 21
 }
... ...
@@ -52,7 +52,7 @@ type Client interface {
52 52
 
53 53
 	Restore(ctx context.Context, containerID string, attachStdio StdioCallback) (alive bool, pid int, p Process, err error)
54 54
 
55
-	Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error
55
+	Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error
56 56
 	Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio StdioCallback) (pid int, err error)
57 57
 	SignalProcess(ctx context.Context, containerID, processID string, signal int) error
58 58
 	Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error)
... ...
@@ -3,12 +3,11 @@ package containerd // import "github.com/docker/docker/plugin/executor/container
3 3
 import (
4 4
 	"context"
5 5
 	"io"
6
-	"path/filepath"
7 6
 	"sync"
8 7
 
9 8
 	"github.com/containerd/containerd"
10 9
 	"github.com/containerd/containerd/cio"
11
-	"github.com/containerd/containerd/runtime/linux/runctypes"
10
+	"github.com/docker/docker/api/types"
12 11
 	"github.com/docker/docker/errdefs"
13 12
 	"github.com/docker/docker/libcontainerd"
14 13
 	libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
... ...
@@ -26,13 +25,14 @@ type ExitHandler interface {
26 26
 }
27 27
 
28 28
 // New creates a new containerd plugin executor
29
-func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, useShimV2 bool) (*Executor, error) {
29
+func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, runtime types.Runtime) (*Executor, error) {
30 30
 	e := &Executor{
31 31
 		rootDir:     rootDir,
32 32
 		exitHandler: exitHandler,
33
+		runtime:     runtime,
33 34
 	}
34 35
 
35
-	client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e, useShimV2)
36
+	client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e)
36 37
 	if err != nil {
37 38
 		return nil, errors.Wrap(err, "error creating containerd exec client")
38 39
 	}
... ...
@@ -45,6 +45,7 @@ type Executor struct {
45 45
 	rootDir     string
46 46
 	client      libcontainerdtypes.Client
47 47
 	exitHandler ExitHandler
48
+	runtime     types.Runtime
48 49
 }
49 50
 
50 51
 // deleteTaskAndContainer deletes plugin task and then plugin container from containerd
... ...
@@ -66,11 +67,8 @@ func deleteTaskAndContainer(ctx context.Context, cli libcontainerdtypes.Client,
66 66
 
67 67
 // Create creates a new container
68 68
 func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteCloser) error {
69
-	opts := runctypes.RuncOptions{
70
-		RuntimeRoot: filepath.Join(e.rootDir, "runtime-root"),
71
-	}
72 69
 	ctx := context.Background()
73
-	err := e.client.Create(ctx, id, &spec, &opts)
70
+	err := e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts)
74 71
 	if err != nil {
75 72
 		status, err2 := e.client.Status(ctx, id)
76 73
 		if err2 != nil {
... ...
@@ -82,7 +80,7 @@ func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteClo
82 82
 				if err2 := e.client.Delete(ctx, id); err2 != nil && !errdefs.IsNotFound(err2) {
83 83
 					logrus.WithError(err2).WithField("plugin", id).Error("Error cleaning up containerd container")
84 84
 				}
85
-				err = e.client.Create(ctx, id, &spec, &opts)
85
+				err = e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts)
86 86
 			}
87 87
 		}
88 88