gopkg.in/docker/docker.v23@v23.0.11/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/pkg/errors"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  const (
    22  	defaultRuntimeName = "runc"
    23  
    24  	linuxShimV2 = "io.containerd.runc.v2"
    25  )
    26  
    27  func configureRuntimes(conf *config.Config) {
    28  	if conf.DefaultRuntime == "" {
    29  		conf.DefaultRuntime = config.StockRuntimeName
    30  	}
    31  	if conf.Runtimes == nil {
    32  		conf.Runtimes = make(map[string]types.Runtime)
    33  	}
    34  	conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)}
    35  	conf.Runtimes[config.StockRuntimeName] = conf.Runtimes[config.LinuxV2RuntimeName]
    36  }
    37  
    38  func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
    39  	return &types.ShimConfig{
    40  		Binary: linuxShimV2,
    41  		Opts: &v2runcoptions.Options{
    42  			BinaryName:    runtimePath,
    43  			Root:          filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
    44  			SystemdCgroup: UsingSystemd(conf),
    45  			NoPivotRoot:   os.Getenv("DOCKER_RAMDISK") != "",
    46  		},
    47  	}
    48  }
    49  
    50  func (daemon *Daemon) loadRuntimes() error {
    51  	return daemon.initRuntimes(daemon.configStore.Runtimes)
    52  }
    53  
    54  func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
    55  	runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
    56  	runtimeOldDir := runtimeDir + "-old"
    57  	// Remove old temp directory if any
    58  	os.RemoveAll(runtimeOldDir)
    59  	tmpDir, err := os.MkdirTemp(daemon.configStore.Root, "gen-runtimes")
    60  	if err != nil {
    61  		return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
    62  	}
    63  	defer func() {
    64  		if err != nil {
    65  			if err1 := os.RemoveAll(tmpDir); err1 != nil {
    66  				logrus.WithError(err1).WithField("dir", tmpDir).
    67  					Warn("failed to remove tmp dir")
    68  			}
    69  			return
    70  		}
    71  
    72  		if err = os.Rename(runtimeDir, runtimeOldDir); err != nil {
    73  			logrus.WithError(err).WithField("dir", runtimeDir).
    74  				Warn("failed to rename runtimes dir to old. Will try to removing it")
    75  			if err = os.RemoveAll(runtimeDir); err != nil {
    76  				logrus.WithError(err).WithField("dir", runtimeDir).
    77  					Warn("failed to remove old runtimes dir")
    78  				return
    79  			}
    80  		}
    81  		if err = os.Rename(tmpDir, runtimeDir); err != nil {
    82  			err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
    83  			return
    84  		}
    85  		if err = os.RemoveAll(runtimeOldDir); err != nil {
    86  			logrus.WithError(err).WithField("dir", runtimeOldDir).
    87  				Warn("failed to remove old runtimes dir")
    88  		}
    89  	}()
    90  
    91  	for name, rt := range runtimes {
    92  		if len(rt.Args) > 0 {
    93  			script := filepath.Join(tmpDir, name)
    94  			content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
    95  			if err := os.WriteFile(script, []byte(content), 0700); err != nil {
    96  				return err
    97  			}
    98  		}
    99  		if rt.Shim == nil {
   100  			rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  // rewriteRuntimePath is used for runtimes which have custom arguments supplied.
   107  // This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments.
   108  // To support this case, the daemon wraps the specified runtime in a script that passes through those arguments.
   109  func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) {
   110  	if len(args) == 0 {
   111  		return p, nil
   112  	}
   113  
   114  	// Check that the runtime path actually exists here so that we can return a well known error.
   115  	if _, err := exec.LookPath(p); err != nil {
   116  		return "", errors.Wrap(err, "error while looking up the specified runtime path")
   117  	}
   118  
   119  	return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
   120  }
   121  
   122  func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) {
   123  	rt := daemon.configStore.GetRuntime(name)
   124  	if rt == nil {
   125  		if !config.IsPermissibleC8dRuntimeName(name) {
   126  			return nil, errdefs.InvalidParameter(errors.Errorf("unknown or invalid runtime name: %s", name))
   127  		}
   128  		return &types.Runtime{Shim: &types.ShimConfig{Binary: name}}, nil
   129  	}
   130  
   131  	if len(rt.Args) > 0 {
   132  		p, err := daemon.rewriteRuntimePath(name, rt.Path, rt.Args)
   133  		if err != nil {
   134  			return nil, err
   135  		}
   136  		rt.Path = p
   137  		rt.Args = nil
   138  	}
   139  
   140  	if rt.Shim == nil {
   141  		rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
   142  	}
   143  
   144  	return rt, nil
   145  }