| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -48,7 +48,7 @@ func (daemon *Daemon) reloadPlatform(conf *config.Config, attributes map[string] |
| 48 | 48 |
if runtimeList.Len() > 0 {
|
| 49 | 49 |
runtimeList.WriteRune(' ')
|
| 50 | 50 |
} |
| 51 |
- runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
|
|
| 51 |
+ runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt.Path))
|
|
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 | 54 |
attributes["runtimes"] = runtimeList.String() |
| 55 | 55 |
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 |
|