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>
This commit is contained in:
parent
6fd94aa933
commit
f63f73a4a8
17 changed files with 238 additions and 178 deletions
|
@ -511,6 +511,16 @@ type Checkpoint struct {
|
|||
type Runtime struct {
|
||||
Path string `json:"path"`
|
||||
Args []string `json:"runtimeArgs,omitempty"`
|
||||
|
||||
// This is exposed here only for internal use
|
||||
// It is not currently supported to specify custom shim configs
|
||||
Shim *ShimConfig `json:"-"`
|
||||
}
|
||||
|
||||
// ShimConfig is used by runtime to configure containerd shims
|
||||
type ShimConfig struct {
|
||||
Binary string
|
||||
Opts interface{}
|
||||
}
|
||||
|
||||
// DiskUsage contains response of Engine API:
|
||||
|
|
|
@ -36,9 +36,6 @@ const (
|
|||
// maximum number of attempts that
|
||||
// may take place at a time for each pull when the connection is lost.
|
||||
DefaultDownloadAttempts = 5
|
||||
// StockRuntimeName is the reserved name/alias used to represent the
|
||||
// OCI runtime being shipped with the docker daemon package.
|
||||
StockRuntimeName = "runc"
|
||||
// DefaultShmSize is the default value for container's shm size
|
||||
DefaultShmSize = int64(67108864)
|
||||
// DefaultNetworkMtu is the default value for network MTU
|
||||
|
@ -47,8 +44,24 @@ const (
|
|||
DisableNetworkBridge = "none"
|
||||
// DefaultInitBinary is the name of the default init binary
|
||||
DefaultInitBinary = "docker-init"
|
||||
|
||||
// StockRuntimeName is the reserved name/alias used to represent the
|
||||
// OCI runtime being shipped with the docker daemon package.
|
||||
StockRuntimeName = "runc"
|
||||
// LinuxV1RuntimeName is the runtime used to specify the containerd v1 shim with the runc binary
|
||||
// Note this is different than io.containerd.runc.v1 which would be the v1 shim using the v2 shim API.
|
||||
// This is specifically for the v1 shim using the v1 shim API.
|
||||
LinuxV1RuntimeName = "io.containerd.runtime.v1.linux"
|
||||
// LinuxV2RuntimeName is the runtime used to specify the containerd v2 runc shim
|
||||
LinuxV2RuntimeName = "io.containerd.runc.v2"
|
||||
)
|
||||
|
||||
var builtinRuntimes = map[string]bool{
|
||||
StockRuntimeName: true,
|
||||
LinuxV1RuntimeName: true,
|
||||
LinuxV2RuntimeName: true,
|
||||
}
|
||||
|
||||
// flatOptions contains configuration keys
|
||||
// that MUST NOT be parsed as deep structures.
|
||||
// Use this to differentiate these options
|
||||
|
@ -571,10 +584,12 @@ func Validate(config *Config) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != StockRuntimeName {
|
||||
runtimes := config.GetAllRuntimes()
|
||||
if _, ok := runtimes[defaultRuntime]; !ok {
|
||||
return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime)
|
||||
if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" {
|
||||
if !builtinRuntimes[defaultRuntime] {
|
||||
runtimes := config.GetAllRuntimes()
|
||||
if _, ok := runtimes[defaultRuntime]; !ok {
|
||||
return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -932,7 +932,11 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
|
|||
}
|
||||
}
|
||||
|
||||
return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, d.useShimV2())
|
||||
var rt types.Runtime
|
||||
if runtime := config.GetRuntime(config.GetDefaultRuntimeName()); runtime != nil {
|
||||
rt = *runtime
|
||||
}
|
||||
return pluginexec.New(ctx, getPluginExecRoot(config.Root), pluginCli, config.ContainerdPluginNamespace, m, rt)
|
||||
}
|
||||
|
||||
// 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
|
|||
|
||||
go d.execCommandGC()
|
||||
|
||||
d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d, d.useShimV2())
|
||||
d.containerd, err = libcontainerd.NewClient(ctx, d.containerdCli, filepath.Join(config.ExecRoot, "containerd"), config.ContainerdNamespace, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
|
@ -78,10 +77,6 @@ const (
|
|||
cgroupFsDriver = "cgroupfs"
|
||||
cgroupSystemdDriver = "systemd"
|
||||
cgroupNoneDriver = "none"
|
||||
|
||||
// DefaultRuntimeName is the default runtime to be used by
|
||||
// containerd if none is specified
|
||||
DefaultRuntimeName = "runc"
|
||||
)
|
||||
|
||||
type containerGetter interface {
|
||||
|
@ -729,57 +724,13 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
|
|||
}
|
||||
}
|
||||
|
||||
if hostConfig.Runtime == config.LinuxV1RuntimeName || (hostConfig.Runtime == "" && daemon.configStore.DefaultRuntime == config.LinuxV1RuntimeName) {
|
||||
warnings = append(warnings, fmt.Sprintf("Configured runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName))
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) loadRuntimes() error {
|
||||
return daemon.initRuntimes(daemon.configStore.Runtimes)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
|
||||
runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
|
||||
// Remove old temp directory if any
|
||||
os.RemoveAll(runtimeDir + "-old")
|
||||
tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err1 := os.RemoveAll(tmpDir); err1 != nil {
|
||||
logrus.WithError(err1).WithField("dir", tmpDir).
|
||||
Warn("failed to remove tmp dir")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil {
|
||||
return
|
||||
}
|
||||
if err = os.Rename(tmpDir, runtimeDir); err != nil {
|
||||
err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
|
||||
return
|
||||
}
|
||||
if err = os.RemoveAll(runtimeDir + "-old"); err != nil {
|
||||
logrus.WithError(err).WithField("dir", tmpDir).
|
||||
Warn("failed to remove old runtimes dir")
|
||||
}
|
||||
}()
|
||||
|
||||
for name, rt := range runtimes {
|
||||
if len(rt.Args) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
script := filepath.Join(tmpDir, name)
|
||||
content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
||||
if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyDaemonSettings performs validation of daemon config struct
|
||||
func verifyDaemonSettings(conf *config.Config) error {
|
||||
if conf.ContainerdNamespace == conf.ContainerdPluginNamespace {
|
||||
|
@ -808,14 +759,15 @@ func verifyDaemonSettings(conf *config.Config) error {
|
|||
return fmt.Errorf("exec-opt native.cgroupdriver=systemd requires cgroup v2 for rootless mode")
|
||||
}
|
||||
|
||||
if conf.DefaultRuntime == "" {
|
||||
conf.DefaultRuntime = config.StockRuntimeName
|
||||
configureRuntimes(conf)
|
||||
if rtName := conf.GetDefaultRuntimeName(); rtName != "" {
|
||||
if conf.GetRuntime(rtName) == nil {
|
||||
return fmt.Errorf("specified default runtime '%s' does not exist", rtName)
|
||||
}
|
||||
if rtName == config.LinuxV1RuntimeName {
|
||||
logrus.Warnf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName)
|
||||
}
|
||||
}
|
||||
if conf.Runtimes == nil {
|
||||
conf.Runtimes = make(map[string]types.Runtime)
|
||||
}
|
||||
conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeName}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1756,10 +1708,6 @@ func (daemon *Daemon) setupSeccompProfile() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) useShimV2() bool {
|
||||
return cgroups.IsCgroup2UnifiedMode()
|
||||
}
|
||||
|
||||
// RawSysInfo returns *sysinfo.SysInfo .
|
||||
func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo {
|
||||
var opts []sysinfo.Opt
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli/debug"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
|
@ -78,6 +79,10 @@ func (daemon *Daemon) SystemInfo() *types.Info {
|
|||
daemon.fillSecurityOptions(v, sysInfo)
|
||||
daemon.fillLicense(v)
|
||||
|
||||
if v.DefaultRuntime == config.LinuxV1RuntimeName {
|
||||
v.Warnings = append(v.Warnings, fmt.Sprintf("Configured default runtime %q is deprecated and will be removed in the next release.", config.LinuxV1RuntimeName))
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
|
|
134
daemon/runtime_unix.go
Normal file
134
daemon/runtime_unix.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
// +build !windows
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultRuntimeName = "runc"
|
||||
|
||||
linuxShimV1 = "io.containerd.runtime.v1.linux"
|
||||
linuxShimV2 = "io.containerd.runc.v2"
|
||||
)
|
||||
|
||||
func configureRuntimes(conf *config.Config) {
|
||||
if conf.DefaultRuntime == "" {
|
||||
conf.DefaultRuntime = config.StockRuntimeName
|
||||
}
|
||||
if conf.Runtimes == nil {
|
||||
conf.Runtimes = make(map[string]types.Runtime)
|
||||
}
|
||||
conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: getShimConfig(conf, defaultRuntimeName)}
|
||||
conf.Runtimes[config.LinuxV1RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV1ShimConfig(conf, defaultRuntimeName)}
|
||||
conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)}
|
||||
}
|
||||
|
||||
func getShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
|
||||
if cgroups.IsCgroup2UnifiedMode() {
|
||||
return defaultV2ShimConfig(conf, runtimePath)
|
||||
}
|
||||
return defaultV1ShimConfig(conf, runtimePath)
|
||||
}
|
||||
|
||||
func defaultV2ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
|
||||
return &types.ShimConfig{
|
||||
Binary: linuxShimV2,
|
||||
Opts: &v2runcoptions.Options{
|
||||
BinaryName: runtimePath,
|
||||
Root: filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
|
||||
SystemdCgroup: UsingSystemd(conf),
|
||||
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func defaultV1ShimConfig(conf *config.Config, runtimePath string) *types.ShimConfig {
|
||||
return &types.ShimConfig{
|
||||
Binary: linuxShimV1,
|
||||
Opts: &runctypes.RuncOptions{
|
||||
Runtime: runtimePath,
|
||||
RuntimeRoot: filepath.Join(conf.ExecRoot, "runtime-"+defaultRuntimeName),
|
||||
SystemdCgroup: UsingSystemd(conf),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) loadRuntimes() error {
|
||||
return daemon.initRuntimes(daemon.configStore.Runtimes)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error) {
|
||||
runtimeDir := filepath.Join(daemon.configStore.Root, "runtimes")
|
||||
// Remove old temp directory if any
|
||||
os.RemoveAll(runtimeDir + "-old")
|
||||
tmpDir, err := ioutils.TempDir(daemon.configStore.Root, "gen-runtimes")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get temp dir to generate runtime scripts")
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err1 := os.RemoveAll(tmpDir); err1 != nil {
|
||||
logrus.WithError(err1).WithField("dir", tmpDir).
|
||||
Warn("failed to remove tmp dir")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err = os.Rename(runtimeDir, runtimeDir+"-old"); err != nil {
|
||||
return
|
||||
}
|
||||
if err = os.Rename(tmpDir, runtimeDir); err != nil {
|
||||
err = errors.Wrap(err, "failed to setup runtimes dir, new containers may not start")
|
||||
return
|
||||
}
|
||||
if err = os.RemoveAll(runtimeDir + "-old"); err != nil {
|
||||
logrus.WithError(err).WithField("dir", tmpDir).
|
||||
Warn("failed to remove old runtimes dir")
|
||||
}
|
||||
}()
|
||||
|
||||
for name, rt := range runtimes {
|
||||
if len(rt.Args) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
script := filepath.Join(tmpDir, name)
|
||||
content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
||||
if err := ioutil.WriteFile(script, []byte(content), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rewriteRuntimePath is used for runtimes which have custom arguments supplied.
|
||||
// This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments.
|
||||
// To support this case, the daemon wraps the specified runtime in a script that passes through those arguments.
|
||||
func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) {
|
||||
if len(args) == 0 {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Check that the runtime path actually exists here so that we can return a well known error.
|
||||
if _, err := exec.LookPath(p); err != nil {
|
||||
return "", errors.Wrap(err, "error while looking up the specified runtime path")
|
||||
}
|
||||
|
||||
return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
|
||||
}
|
|
@ -175,7 +175,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
|
|||
}
|
||||
}
|
||||
|
||||
createOptions, err := daemon.getLibcontainerdCreateOptions(container)
|
||||
shim, createOptions, err := daemon.getLibcontainerdCreateOptions(container)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
|
|||
return err
|
||||
}
|
||||
|
||||
err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String()))
|
||||
err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String()))
|
||||
if err != nil {
|
||||
if errdefs.IsConflict(err) {
|
||||
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
|
|||
if err := daemon.containerd.Delete(ctx, container.ID); err != nil && !errdefs.IsNotFound(err) {
|
||||
logrus.WithError(err).WithField("container", container.ID).Error("Error cleaning up stale containerd container object")
|
||||
}
|
||||
err = daemon.containerd.Create(ctx, container.ID, spec, createOptions, withImageName(imageRef.String()))
|
||||
err = daemon.containerd.Create(ctx, container.ID, spec, shim, createOptions, withImageName(imageRef.String()))
|
||||
}
|
||||
if err != nil {
|
||||
return translateContainerdStartErr(container.Path, container.SetExitCode, err)
|
||||
|
|
|
@ -3,70 +3,35 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getRuntimeScript(container *container.Container) (string, error) {
|
||||
name := container.HostConfig.Runtime
|
||||
rt := daemon.configStore.GetRuntime(name)
|
||||
if rt == nil {
|
||||
return "", errdefs.InvalidParameter(errors.Errorf("no such runtime '%s'", name))
|
||||
}
|
||||
|
||||
if len(rt.Args) > 0 {
|
||||
// First check that the target exist, as using it in a script won't
|
||||
// give us the right error
|
||||
if _, err := exec.LookPath(rt.Path); err != nil {
|
||||
return "", translateContainerdStartErr(container.Path, container.SetExitCode, err)
|
||||
}
|
||||
return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
|
||||
}
|
||||
return rt.Path, nil
|
||||
}
|
||||
|
||||
// getLibcontainerdCreateOptions callers must hold a lock on the container
|
||||
func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) {
|
||||
func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) {
|
||||
// Ensure a runtime has been assigned to this container
|
||||
if container.HostConfig.Runtime == "" {
|
||||
container.HostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
|
||||
container.CheckpointTo(daemon.containersReplica)
|
||||
}
|
||||
|
||||
path, err := daemon.getRuntimeScript(container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if daemon.useShimV2() {
|
||||
opts := &v2runcoptions.Options{
|
||||
BinaryName: path,
|
||||
Root: filepath.Join(daemon.configStore.ExecRoot,
|
||||
fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)),
|
||||
rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime)
|
||||
if rt.Shim == nil {
|
||||
p, err := daemon.rewriteRuntimePath(container.HostConfig.Runtime, rt.Path, rt.Args)
|
||||
if err != nil {
|
||||
return "", nil, translateContainerdStartErr(container.Path, container.SetExitCode, err)
|
||||
}
|
||||
|
||||
if UsingSystemd(daemon.configStore) {
|
||||
opts.SystemdCgroup = true
|
||||
rt.Shim = getShimConfig(daemon.configStore, p)
|
||||
}
|
||||
if rt.Shim.Binary == linuxShimV1 {
|
||||
if cgroups.IsCgroup2UnifiedMode() {
|
||||
return "", nil, errdefs.InvalidParameter(errors.Errorf("runtime %q is not supported while cgroups v2 (unified hierarchy) is being used", container.HostConfig.Runtime))
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
|
||||
}
|
||||
opts := &runctypes.RuncOptions{
|
||||
Runtime: path,
|
||||
RuntimeRoot: filepath.Join(daemon.configStore.ExecRoot,
|
||||
fmt.Sprintf("runtime-%s", container.HostConfig.Runtime)),
|
||||
logrus.Warnf("Configured runtime %q is deprecated and will be removed in the next release", container.HostConfig.Runtime)
|
||||
}
|
||||
|
||||
if UsingSystemd(daemon.configStore) {
|
||||
opts.SystemdCgroup = true
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
return rt.Shim.Binary, rt.Shim.Opts, nil
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) {
|
||||
func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (string, interface{}, error) {
|
||||
|
||||
// Set the runtime options to debug regardless of current logging level.
|
||||
if system.ContainerdRuntimeSupported() {
|
||||
opts := &options.Options{Debug: true}
|
||||
return opts, nil
|
||||
return "", opts, nil
|
||||
}
|
||||
|
||||
// TODO (containerd) - Probably need to revisit LCOW options here
|
||||
|
@ -22,7 +22,7 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
if container.OS == "linux" {
|
||||
config := &client.Config{}
|
||||
if err := config.GenerateDefault(daemon.configStore.GraphOptions); err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
// Override from user-supplied options.
|
||||
for k, v := range container.HostConfig.StorageOpt {
|
||||
|
@ -34,11 +34,11 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
}
|
||||
}
|
||||
if err := config.Validate(); err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
return "", config, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
return "", nil, nil
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func (c *MockContainerdClient) Version(ctx context.Context) (containerd.Version,
|
|||
func (c *MockContainerdClient) Restore(ctx context.Context, containerID string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, p libcontainerdtypes.Process, err error) {
|
||||
return false, 0, &mockProcess{}, nil
|
||||
}
|
||||
func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
return nil
|
||||
}
|
||||
func (c *MockContainerdClient) Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error) {
|
||||
|
|
|
@ -9,6 +9,6 @@ import (
|
|||
)
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2)
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ import (
|
|||
)
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
if !system.ContainerdRuntimeSupported() {
|
||||
// useShimV2 is ignored for windows
|
||||
return local.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b, useShimV2)
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) {
|
|||
// "ImagePath": "C:\\\\control\\\\windowsfilter\\\\65bf96e5760a09edf1790cb229e2dfb2dbd0fcdc0bf7451bae099106bfbfea0c\\\\UtilityVM"
|
||||
// },
|
||||
// }
|
||||
func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
func (c *client) Create(_ context.Context, id string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
if ctr := c.getContainer(id); ctr != nil {
|
||||
return errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
|
|
|
@ -50,14 +50,13 @@ type client struct {
|
|||
eventQ queue.Queue
|
||||
oomMu sync.Mutex
|
||||
oom map[string]bool
|
||||
useShimV2 bool
|
||||
v2runcoptionsMu sync.Mutex
|
||||
// v2runcoptions is used for copying options specified on Create() to Start()
|
||||
v2runcoptions map[string]v2runcoptions.Options
|
||||
}
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend, useShimV2 bool) (libcontainerdtypes.Client, error) {
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
c := &client{
|
||||
client: cli,
|
||||
stateDir: stateDir,
|
||||
|
@ -65,7 +64,6 @@ func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string,
|
|||
ns: ns,
|
||||
backend: b,
|
||||
oom: make(map[string]bool),
|
||||
useShimV2: useShimV2,
|
||||
v2runcoptions: make(map[string]v2runcoptions.Options),
|
||||
}
|
||||
|
||||
|
@ -129,17 +127,13 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio libcontaine
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error {
|
||||
bdir := c.bundleDir(id)
|
||||
c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created")
|
||||
|
||||
rt := runtimeName
|
||||
if c.useShimV2 {
|
||||
rt = shimV2RuntimeName
|
||||
}
|
||||
newOpts := []containerd.NewContainerOpts{
|
||||
containerd.WithSpec(ociSpec),
|
||||
containerd.WithRuntime(rt, runtimeOptions),
|
||||
containerd.WithRuntime(shim, runtimeOptions),
|
||||
WithBundle(bdir, ociSpec),
|
||||
}
|
||||
opts = append(opts, newOpts...)
|
||||
|
@ -151,12 +145,10 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run
|
|||
}
|
||||
return wrapError(err)
|
||||
}
|
||||
if c.useShimV2 {
|
||||
if x, ok := runtimeOptions.(*v2runcoptions.Options); ok {
|
||||
c.v2runcoptionsMu.Lock()
|
||||
c.v2runcoptions[id] = *x
|
||||
c.v2runcoptionsMu.Unlock()
|
||||
}
|
||||
if x, ok := runtimeOptions.(*v2runcoptions.Options); ok {
|
||||
c.v2runcoptionsMu.Lock()
|
||||
c.v2runcoptions[id] = *x
|
||||
c.v2runcoptionsMu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -218,17 +210,12 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
|
|||
|
||||
if runtime.GOOS != "windows" {
|
||||
taskOpts = append(taskOpts, func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
|
||||
if c.useShimV2 {
|
||||
// For v2, we need to inherit options specified on Create
|
||||
c.v2runcoptionsMu.Lock()
|
||||
opts, ok := c.v2runcoptions[id]
|
||||
c.v2runcoptionsMu.Unlock()
|
||||
if !ok {
|
||||
opts = v2runcoptions.Options{}
|
||||
}
|
||||
c.v2runcoptionsMu.Lock()
|
||||
opts, ok := c.v2runcoptions[id]
|
||||
c.v2runcoptionsMu.Unlock()
|
||||
if ok {
|
||||
opts.IoUid = uint32(uid)
|
||||
opts.IoGid = uint32(gid)
|
||||
opts.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
||||
info.Options = &opts
|
||||
} else {
|
||||
info.Options = &runctypes.CreateOptions{
|
||||
|
@ -237,7 +224,6 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
|
|||
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
|
|
|
@ -16,11 +16,6 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
runtimeName = "io.containerd.runtime.v1.linux"
|
||||
shimV2RuntimeName = "io.containerd.runc.v2"
|
||||
)
|
||||
|
||||
func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
|
||||
return &libcontainerdtypes.Summary{}, nil
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ type Client interface {
|
|||
|
||||
Restore(ctx context.Context, containerID string, attachStdio StdioCallback) (alive bool, pid int, p Process, err error)
|
||||
|
||||
Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error
|
||||
Create(ctx context.Context, containerID string, spec *specs.Spec, shim string, runtimeOptions interface{}, opts ...containerd.NewContainerOpts) error
|
||||
Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio StdioCallback) (pid int, err error)
|
||||
SignalProcess(ctx context.Context, containerID, processID string, signal int) error
|
||||
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
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
|
@ -26,13 +25,14 @@ type ExitHandler interface {
|
|||
}
|
||||
|
||||
// New creates a new containerd plugin executor
|
||||
func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, useShimV2 bool) (*Executor, error) {
|
||||
func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, runtime types.Runtime) (*Executor, error) {
|
||||
e := &Executor{
|
||||
rootDir: rootDir,
|
||||
exitHandler: exitHandler,
|
||||
runtime: runtime,
|
||||
}
|
||||
|
||||
client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e, useShimV2)
|
||||
client, err := libcontainerd.NewClient(ctx, cli, rootDir, ns, e)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating containerd exec client")
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ type Executor struct {
|
|||
rootDir string
|
||||
client libcontainerdtypes.Client
|
||||
exitHandler ExitHandler
|
||||
runtime types.Runtime
|
||||
}
|
||||
|
||||
// deleteTaskAndContainer deletes plugin task and then plugin container from containerd
|
||||
|
@ -66,11 +67,8 @@ func deleteTaskAndContainer(ctx context.Context, cli libcontainerdtypes.Client,
|
|||
|
||||
// Create creates a new container
|
||||
func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteCloser) error {
|
||||
opts := runctypes.RuncOptions{
|
||||
RuntimeRoot: filepath.Join(e.rootDir, "runtime-root"),
|
||||
}
|
||||
ctx := context.Background()
|
||||
err := e.client.Create(ctx, id, &spec, &opts)
|
||||
err := e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts)
|
||||
if err != nil {
|
||||
status, err2 := e.client.Status(ctx, id)
|
||||
if err2 != nil {
|
||||
|
@ -82,7 +80,7 @@ func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteClo
|
|||
if err2 := e.client.Delete(ctx, id); err2 != nil && !errdefs.IsNotFound(err2) {
|
||||
logrus.WithError(err2).WithField("plugin", id).Error("Error cleaning up containerd container")
|
||||
}
|
||||
err = e.client.Create(ctx, id, &spec, &opts)
|
||||
err = e.client.Create(ctx, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue