github.com/afbjorklund/moby@v20.10.5+incompatible/daemon/runtime_unix.go (about)

     1  // +build !windows
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/containerd/cgroups"
    14  	"github.com/containerd/containerd/runtime/linux/runctypes"
    15  	v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
    16  	"github.com/docker/docker/api/types"
    17  	"github.com/docker/docker/daemon/config"
    18  	"github.com/docker/docker/errdefs"
    19  	"github.com/docker/docker/pkg/ioutils"
    20  	"github.com/pkg/errors"
    21  	"github.com/sirupsen/logrus"
    22  )
    23  
    24  const (
    25  	defaultRuntimeName = "runc"
    26  
    27  	linuxShimV1 = "io.containerd.runtime.v1.linux"
    28  	linuxShimV2 = "io.containerd.runc.v2"
    29  )
    30  
    31  func configureRuntimes(conf *config.Config) {
    32  	if conf.DefaultRuntime == "" {
    33  		conf.DefaultRuntime = config.StockRuntimeName
    34  	}
    35  	if conf.Runtimes == nil {
    36  		conf.Runtimes = make(map[string]types.Runtime)
    37  	}
    38  	conf.Runtimes[config.LinuxV1RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV1ShimConfig(conf, defaultRuntimeName)}
    39  	conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)}
    40  	conf.Runtimes[config.StockRuntimeName] = conf.Runtimes[config.LinuxV2RuntimeName]
    41  }
    42  
    43  func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
    44  	return &types.ShimConfig{
    45  		Binary: linuxShimV2,
    46  		Opts: &v2runcoptions.Options{
    47  			BinaryName:    runtimePath,
    48  			Root:          filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
    49  			SystemdCgroup: UsingSystemd(conf),
    50  			NoPivotRoot:   os.Getenv("DOCKER_RAMDISK") != "",
    51  		},
    52  	}
    53  }
    54  
    55  func defaultV1ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
    56  	return &types.ShimConfig{
    57  		Binary: linuxShimV1,
    58  		Opts: &runctypes.RuncOptions{
    59  			Runtime:       runtimePath,
    60  			RuntimeRoot:   filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
    61  			SystemdCgroup: UsingSystemd(conf),
    62  		},
    63  	}
    64  }
    65  
    66  func (daemon *Daemon) loadRuntimes() error {
    67  	return daemon.initRuntimes(daemon.configStore.Runtimes)
    68  }
    69  
    70  func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
    71  	runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
    72  	// Remove old temp directory if any
    73  	os.RemoveAll(runtimeDir + "-old")
    74  	tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes")
    75  	if err != nil {
    76  		return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
    77  	}
    78  	defer func() {
    79  		if err != nil {
    80  			if err1 := os.RemoveAll(tmpDir); err1 != nil {
    81  				logrus.WithError(err1).WithField("dir", tmpDir).
    82  					Warn("failed to remove tmp dir")
    83  			}
    84  			return
    85  		}
    86  
    87  		if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil {
    88  			return
    89  		}
    90  		if err = os.Rename(tmpDir, runtimeDir); err != nil {
    91  			err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
    92  			return
    93  		}
    94  		if err = os.RemoveAll(runtimeDir + "-old"); err != nil {
    95  			logrus.WithError(err).WithField("dir", tmpDir).
    96  				Warn("failed to remove old runtimes dir")
    97  		}
    98  	}()
    99  
   100  	for name, rt := range runtimes {
   101  		if len(rt.Args) > 0 {
   102  			script := filepath.Join(tmpDir, name)
   103  			content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
   104  			if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
   105  				return err
   106  			}
   107  		}
   108  		if rt.Shim == nil {
   109  			rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  // rewriteRuntimePath is used for runtimes which have custom arguments supplied.
   116  // This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments.
   117  // To support this case, the daemon wraps the specified runtime in a script that passes through those arguments.
   118  func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) {
   119  	if len(args) == 0 {
   120  		return p, nil
   121  	}
   122  
   123  	// Check that the runtime path actually exists here so that we can return a well known error.
   124  	if _, err := exec.LookPath(p); err != nil {
   125  		return "", errors.Wrap(err, "error while looking up the specified runtime path")
   126  	}
   127  
   128  	return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
   129  }
   130  
   131  func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) {
   132  	rt := daemon.configStore.GetRuntime(name)
   133  	if rt == nil {
   134  		return nil, errdefs.InvalidParameter(errors.Errorf("runtime not found in config: %s", name))
   135  	}
   136  
   137  	if len(rt.Args) > 0 {
   138  		p, err := daemon.rewriteRuntimePath(name, rt.Path, rt.Args)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		rt.Path = p
   143  		rt.Args = nil
   144  	}
   145  
   146  	if rt.Shim == nil {
   147  		rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
   148  	}
   149  
   150  	if rt.Shim.Binary == linuxShimV1 {
   151  		if cgroups.Mode() == cgroups.Unified {
   152  			return nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", name))
   153  		}
   154  		logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", name)
   155  	}
   156  
   157  	return rt, nil
   158  }