github.com/rawahars/moby@v24.0.4+incompatible/daemon/runtime_unix.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package daemon 5 6 import ( 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 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/errdefs" 17 "github.com/docker/docker/libcontainerd/shimopts" 18 "github.com/pkg/errors" 19 "github.com/sirupsen/logrus" 20 ) 21 22 const ( 23 defaultRuntimeName = "runc" 24 25 linuxShimV2 = "io.containerd.runc.v2" 26 ) 27 28 func configureRuntimes(conf *config.Config) { 29 if conf.DefaultRuntime == "" { 30 conf.DefaultRuntime = config.StockRuntimeName 31 } 32 if conf.Runtimes == nil { 33 conf.Runtimes = make(map[string]types.Runtime) 34 } 35 conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, ShimConfig: defaultV2ShimConfig(conf, defaultRuntimeName)} 36 conf.Runtimes[config.StockRuntimeName] = conf.Runtimes[config.LinuxV2RuntimeName] 37 } 38 39 func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig { 40 return &types.ShimConfig{ 41 Binary: linuxShimV2, 42 Opts: &v2runcoptions.Options{ 43 BinaryName: runtimePath, 44 Root: filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName), 45 SystemdCgroup: UsingSystemd(conf), 46 NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "", 47 }, 48 } 49 } 50 51 func (daemon *Daemon) loadRuntimes() error { 52 return daemon.initRuntimes(daemon.configStore.Runtimes) 53 } 54 55 func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) { 56 runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes") 57 runtimeOldDir := runtimeDir + "-old" 58 // Remove old temp directory if any 59 os.RemoveAll(runtimeOldDir) 60 tmpDir, err := os.MkdirTemp(daemon.configStore.Root, "gen-runtimes") 61 if err != nil { 62 return errors.Wrap(err, "failed to get temp dir to generate runtime scripts") 63 } 64 defer func() { 65 if err != nil { 66 if err1 := os.RemoveAll(tmpDir); err1 != nil { 67 logrus.WithError(err1).WithField("dir", tmpDir). 68 Warn("failed to remove tmp dir") 69 } 70 return 71 } 72 73 if err = os.Rename(runtimeDir, runtimeOldDir); err != nil { 74 logrus.WithError(err).WithField("dir", runtimeDir). 75 Warn("failed to rename runtimes dir to old. Will try to removing it") 76 if err = os.RemoveAll(runtimeDir); err != nil { 77 logrus.WithError(err).WithField("dir", runtimeDir). 78 Warn("failed to remove old runtimes dir") 79 return 80 } 81 } 82 if err = os.Rename(tmpDir, runtimeDir); err != nil { 83 err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start") 84 return 85 } 86 if err = os.RemoveAll(runtimeOldDir); err != nil { 87 logrus.WithError(err).WithField("dir", runtimeOldDir). 88 Warn("failed to remove old runtimes dir") 89 } 90 }() 91 92 for name := range runtimes { 93 rt := runtimes[name] 94 if rt.Path == "" && rt.Type == "" { 95 return errors.Errorf("runtime %s: either a runtimeType or a path must be configured", name) 96 } 97 if rt.Path != "" { 98 if rt.Type != "" { 99 return errors.Errorf("runtime %s: cannot configure both path and runtimeType for the same runtime", name) 100 } 101 if len(rt.Options) > 0 { 102 return errors.Errorf("runtime %s: options cannot be used with a path runtime", name) 103 } 104 105 if len(rt.Args) > 0 { 106 script := filepath.Join(tmpDir, name) 107 content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " ")) 108 if err := os.WriteFile(script, []byte(content), 0700); err != nil { 109 return err 110 } 111 } 112 rt.ShimConfig = defaultV2ShimConfig(daemon.configStore, daemon.rewriteRuntimePath(name, rt.Path, rt.Args)) 113 } else { 114 if len(rt.Args) > 0 { 115 return errors.Errorf("runtime %s: args cannot be used with a runtimeType runtime", name) 116 } 117 // Unlike implicit runtimes, there is no restriction on configuring a shim by path. 118 rt.ShimConfig = &types.ShimConfig{Binary: rt.Type} 119 if len(rt.Options) > 0 { 120 // It has to be a pointer type or there'll be a panic in containerd/typeurl when we try to start the container. 121 rt.ShimConfig.Opts, err = shimopts.Generate(rt.Type, rt.Options) 122 if err != nil { 123 return errors.Wrapf(err, "runtime %v", name) 124 } 125 } 126 } 127 runtimes[name] = rt 128 } 129 return nil 130 } 131 132 // rewriteRuntimePath is used for runtimes which have custom arguments supplied. 133 // This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments. 134 // To support this case, the daemon wraps the specified runtime in a script that passes through those arguments. 135 func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) string { 136 if len(args) == 0 { 137 return p 138 } 139 140 return filepath.Join(daemon.configStore.Root, "runtimes", name) 141 } 142 143 func (daemon *Daemon) getRuntime(name string) (shim string, opts interface{}, err error) { 144 rt := daemon.configStore.GetRuntime(name) 145 if rt == nil { 146 if !config.IsPermissibleC8dRuntimeName(name) { 147 return "", nil, errdefs.InvalidParameter(errors.Errorf("unknown or invalid runtime name: %s", name)) 148 } 149 return name, nil, nil 150 } 151 152 if len(rt.Args) > 0 { 153 // Check that the path of the runtime which the script wraps actually exists so 154 // that we can return a well known error which references the configured path 155 // instead of the wrapper script's. 156 if _, err := exec.LookPath(rt.Path); err != nil { 157 return "", nil, errors.Wrap(err, "error while looking up the specified runtime path") 158 } 159 } 160 161 if rt.ShimConfig == nil { 162 // Should never happen as daemon.initRuntimes always sets 163 // ShimConfig and config reloading is synchronized. 164 err := errdefs.System(errors.Errorf("BUG: runtime %s: rt.ShimConfig == nil", name)) 165 logrus.Error(err) 166 return "", nil, err 167 } 168 169 return rt.ShimConfig.Binary, rt.ShimConfig.Opts, nil 170 }