Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
| ... | ... |
@@ -55,7 +55,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
| 55 | 55 |
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver) |
| 56 | 56 |
ioutils.FprintfIfNotEmpty(cli.out, "Cgroup Driver: %s\n", info.CgroupDriver) |
| 57 | 57 |
|
| 58 |
- fmt.Fprintf(cli.out, "Plugins: \n") |
|
| 58 |
+ fmt.Fprintf(cli.out, "Plugins:\n") |
|
| 59 | 59 |
fmt.Fprintf(cli.out, " Volume:") |
| 60 | 60 |
fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Volume, " ")) |
| 61 | 61 |
fmt.Fprintf(cli.out, "\n") |
| ... | ... |
@@ -84,6 +84,16 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
| 84 | 84 |
fmt.Fprintf(cli.out, " IsManager: No\n") |
| 85 | 85 |
} |
| 86 | 86 |
} |
| 87 |
+ |
|
| 88 |
+ if len(info.Runtimes) > 0 {
|
|
| 89 |
+ fmt.Fprintf(cli.out, "Runtimes:") |
|
| 90 |
+ for name := range info.Runtimes {
|
|
| 91 |
+ fmt.Fprintf(cli.out, " %s", name) |
|
| 92 |
+ } |
|
| 93 |
+ fmt.Fprint(cli.out, "\n") |
|
| 94 |
+ fmt.Fprintf(cli.out, "Default Runtime: %s\n", info.DefaultRuntime) |
|
| 95 |
+ } |
|
| 96 |
+ |
|
| 87 | 97 |
ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion) |
| 88 | 98 |
ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem) |
| 89 | 99 |
ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType) |
| ... | ... |
@@ -388,6 +388,10 @@ func loadDaemonCliConfig(config *daemon.Config, flags *flag.FlagSet, commonConfi |
| 388 | 388 |
} |
| 389 | 389 |
} |
| 390 | 390 |
|
| 391 |
+ if err := daemon.ValidateConfiguration(config); err != nil {
|
|
| 392 |
+ return nil, err |
|
| 393 |
+ } |
|
| 394 |
+ |
|
| 391 | 395 |
// Regardless of whether the user sets it to true or false, if they |
| 392 | 396 |
// specify TLSVerify at all then we need to turn on TLS |
| 393 | 397 |
if config.IsValueSet(cliflags.TLSVerifyKey) {
|
| ... | ... |
@@ -74,6 +74,7 @@ func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption {
|
| 74 | 74 |
if cli.Config.LiveRestore {
|
| 75 | 75 |
opts = append(opts, libcontainerd.WithLiveRestore(true)) |
| 76 | 76 |
} |
| 77 |
+ opts = append(opts, libcontainerd.WithRuntimePath(daemon.DefaultRuntimeBinary)) |
|
| 77 | 78 |
return opts |
| 78 | 79 |
} |
| 79 | 80 |
|
| ... | ... |
@@ -14,6 +14,7 @@ import ( |
| 14 | 14 |
"github.com/docker/docker/pkg/discovery" |
| 15 | 15 |
flag "github.com/docker/docker/pkg/mflag" |
| 16 | 16 |
"github.com/docker/docker/registry" |
| 17 |
+ "github.com/docker/engine-api/types" |
|
| 17 | 18 |
"github.com/imdario/mergo" |
| 18 | 19 |
) |
| 19 | 20 |
|
| ... | ... |
@@ -40,6 +41,7 @@ const ( |
| 40 | 40 |
var flatOptions = map[string]bool{
|
| 41 | 41 |
"cluster-store-opts": true, |
| 42 | 42 |
"log-opts": true, |
| 43 |
+ "runtimes": true, |
|
| 43 | 44 |
} |
| 44 | 45 |
|
| 45 | 46 |
// LogConfig represents the default log configuration. |
| ... | ... |
@@ -200,7 +202,7 @@ func ReloadConfiguration(configFile string, flags *flag.FlagSet, reload func(*Co |
| 200 | 200 |
return err |
| 201 | 201 |
} |
| 202 | 202 |
|
| 203 |
- if err := validateConfiguration(newConfig); err != nil {
|
|
| 203 |
+ if err := ValidateConfiguration(newConfig); err != nil {
|
|
| 204 | 204 |
return fmt.Errorf("file configuration validation failed (%v)", err)
|
| 205 | 205 |
} |
| 206 | 206 |
|
| ... | ... |
@@ -224,7 +226,7 @@ func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configF |
| 224 | 224 |
return nil, err |
| 225 | 225 |
} |
| 226 | 226 |
|
| 227 |
- if err := validateConfiguration(fileConfig); err != nil {
|
|
| 227 |
+ if err := ValidateConfiguration(fileConfig); err != nil {
|
|
| 228 | 228 |
return nil, fmt.Errorf("file configuration validation failed (%v)", err)
|
| 229 | 229 |
} |
| 230 | 230 |
|
| ... | ... |
@@ -233,6 +235,12 @@ func MergeDaemonConfigurations(flagsConfig *Config, flags *flag.FlagSet, configF |
| 233 | 233 |
return nil, err |
| 234 | 234 |
} |
| 235 | 235 |
|
| 236 |
+ // We need to validate again once both fileConfig and flagsConfig |
|
| 237 |
+ // have been merged |
|
| 238 |
+ if err := ValidateConfiguration(fileConfig); err != nil {
|
|
| 239 |
+ return nil, fmt.Errorf("file configuration validation failed (%v)", err)
|
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 236 | 242 |
return fileConfig, nil |
| 237 | 243 |
} |
| 238 | 244 |
|
| ... | ... |
@@ -381,10 +389,10 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS
|
| 381 | 381 |
return nil |
| 382 | 382 |
} |
| 383 | 383 |
|
| 384 |
-// validateConfiguration validates some specific configs. |
|
| 384 |
+// ValidateConfiguration validates some specific configs. |
|
| 385 | 385 |
// such as config.DNS, config.Labels, config.DNSSearch, |
| 386 | 386 |
// as well as config.MaxConcurrentDownloads, config.MaxConcurrentUploads. |
| 387 |
-func validateConfiguration(config *Config) error {
|
|
| 387 |
+func ValidateConfiguration(config *Config) error {
|
|
| 388 | 388 |
// validate DNS |
| 389 | 389 |
for _, dns := range config.DNS {
|
| 390 | 390 |
if _, err := opts.ValidateIPAddress(dns); err != nil {
|
| ... | ... |
@@ -415,5 +423,20 @@ func validateConfiguration(config *Config) error {
|
| 415 | 415 |
if config.IsValueSet("max-concurrent-uploads") && config.MaxConcurrentUploads != nil && *config.MaxConcurrentUploads < 0 {
|
| 416 | 416 |
return fmt.Errorf("invalid max concurrent uploads: %d", *config.MaxConcurrentUploads)
|
| 417 | 417 |
} |
| 418 |
+ |
|
| 419 |
+ // validate that "default" runtime is not reset |
|
| 420 |
+ if runtimes := config.GetAllRuntimes(); len(runtimes) > 0 {
|
|
| 421 |
+ if _, ok := runtimes[types.DefaultRuntimeName]; ok {
|
|
| 422 |
+ return fmt.Errorf("runtime name '%s' is reserved", types.DefaultRuntimeName)
|
|
| 423 |
+ } |
|
| 424 |
+ } |
|
| 425 |
+ |
|
| 426 |
+ if defaultRuntime := config.GetDefaultRuntimeName(); defaultRuntime != "" && defaultRuntime != types.DefaultRuntimeName {
|
|
| 427 |
+ runtimes := config.GetAllRuntimes() |
|
| 428 |
+ if _, ok := runtimes[defaultRuntime]; !ok {
|
|
| 429 |
+ return fmt.Errorf("specified default runtime '%s' does not exist", defaultRuntime)
|
|
| 430 |
+ } |
|
| 431 |
+ } |
|
| 432 |
+ |
|
| 418 | 433 |
return nil |
| 419 | 434 |
} |
| ... | ... |
@@ -216,7 +216,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 216 | 216 |
}, |
| 217 | 217 |
} |
| 218 | 218 |
|
| 219 |
- err := validateConfiguration(c1) |
|
| 219 |
+ err := ValidateConfiguration(c1) |
|
| 220 | 220 |
if err == nil {
|
| 221 | 221 |
t.Fatal("expected error, got nil")
|
| 222 | 222 |
} |
| ... | ... |
@@ -227,7 +227,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 227 | 227 |
}, |
| 228 | 228 |
} |
| 229 | 229 |
|
| 230 |
- err = validateConfiguration(c2) |
|
| 230 |
+ err = ValidateConfiguration(c2) |
|
| 231 | 231 |
if err != nil {
|
| 232 | 232 |
t.Fatalf("expected no error, got error %v", err)
|
| 233 | 233 |
} |
| ... | ... |
@@ -238,7 +238,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 238 | 238 |
}, |
| 239 | 239 |
} |
| 240 | 240 |
|
| 241 |
- err = validateConfiguration(c3) |
|
| 241 |
+ err = ValidateConfiguration(c3) |
|
| 242 | 242 |
if err != nil {
|
| 243 | 243 |
t.Fatalf("expected no error, got error %v", err)
|
| 244 | 244 |
} |
| ... | ... |
@@ -249,7 +249,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 249 | 249 |
}, |
| 250 | 250 |
} |
| 251 | 251 |
|
| 252 |
- err = validateConfiguration(c4) |
|
| 252 |
+ err = ValidateConfiguration(c4) |
|
| 253 | 253 |
if err == nil {
|
| 254 | 254 |
t.Fatal("expected error, got nil")
|
| 255 | 255 |
} |
| ... | ... |
@@ -260,7 +260,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 260 | 260 |
}, |
| 261 | 261 |
} |
| 262 | 262 |
|
| 263 |
- err = validateConfiguration(c5) |
|
| 263 |
+ err = ValidateConfiguration(c5) |
|
| 264 | 264 |
if err != nil {
|
| 265 | 265 |
t.Fatalf("expected no error, got error %v", err)
|
| 266 | 266 |
} |
| ... | ... |
@@ -271,7 +271,7 @@ func TestValidateConfiguration(t *testing.T) {
|
| 271 | 271 |
}, |
| 272 | 272 |
} |
| 273 | 273 |
|
| 274 |
- err = validateConfiguration(c6) |
|
| 274 |
+ err = ValidateConfiguration(c6) |
|
| 275 | 275 |
if err == nil {
|
| 276 | 276 |
t.Fatal("expected error, got nil")
|
| 277 | 277 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"github.com/docker/docker/opts" |
| 9 | 9 |
flag "github.com/docker/docker/pkg/mflag" |
| 10 | 10 |
runconfigopts "github.com/docker/docker/runconfig/opts" |
| 11 |
+ "github.com/docker/engine-api/types" |
|
| 11 | 12 |
"github.com/docker/go-units" |
| 12 | 13 |
) |
| 13 | 14 |
|
| ... | ... |
@@ -30,6 +31,8 @@ type Config struct {
|
| 30 | 30 |
ExecRoot string `json:"exec-root,omitempty"` |
| 31 | 31 |
RemappedRoot string `json:"userns-remap,omitempty"` |
| 32 | 32 |
Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"` |
| 33 |
+ Runtimes map[string]types.Runtime `json:"runtimes,omitempty"` |
|
| 34 |
+ DefaultRuntime string `json:"default-runtime,omitempty"` |
|
| 33 | 35 |
} |
| 34 | 36 |
|
| 35 | 37 |
// bridgeConfig stores all the bridge driver specific |
| ... | ... |
@@ -83,6 +86,37 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
| 83 | 83 |
cmd.StringVar(&config.RemappedRoot, []string{"-userns-remap"}, "", usageFn("User/Group setting for user namespaces"))
|
| 84 | 84 |
cmd.StringVar(&config.ContainerdAddr, []string{"-containerd"}, "", usageFn("Path to containerd socket"))
|
| 85 | 85 |
cmd.BoolVar(&config.LiveRestore, []string{"-live-restore"}, false, usageFn("Enable live restore of docker when containers are still running"))
|
| 86 |
+ config.Runtimes = make(map[string]types.Runtime) |
|
| 87 |
+ cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime"))
|
|
| 88 |
+ cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, types.DefaultRuntimeName, usageFn("Default OCI runtime to be used"))
|
|
| 86 | 89 |
|
| 87 | 90 |
config.attachExperimentalFlags(cmd, usageFn) |
| 88 | 91 |
} |
| 92 |
+ |
|
| 93 |
+// GetRuntime returns the runtime path and arguments for a given |
|
| 94 |
+// runtime name |
|
| 95 |
+func (config *Config) GetRuntime(name string) *types.Runtime {
|
|
| 96 |
+ config.reloadLock.Lock() |
|
| 97 |
+ defer config.reloadLock.Unlock() |
|
| 98 |
+ if rt, ok := config.Runtimes[name]; ok {
|
|
| 99 |
+ return &rt |
|
| 100 |
+ } |
|
| 101 |
+ return nil |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+// GetDefaultRuntimeName returns the current default runtime |
|
| 105 |
+func (config *Config) GetDefaultRuntimeName() string {
|
|
| 106 |
+ config.reloadLock.Lock() |
|
| 107 |
+ rt := config.DefaultRuntime |
|
| 108 |
+ config.reloadLock.Unlock() |
|
| 109 |
+ |
|
| 110 |
+ return rt |
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
| 114 |
+func (config *Config) GetAllRuntimes() map[string]types.Runtime {
|
|
| 115 |
+ config.reloadLock.Lock() |
|
| 116 |
+ rts := config.Runtimes |
|
| 117 |
+ config.reloadLock.Unlock() |
|
| 118 |
+ return rts |
|
| 119 |
+} |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"os" |
| 5 | 5 |
|
| 6 | 6 |
flag "github.com/docker/docker/pkg/mflag" |
| 7 |
+ "github.com/docker/engine-api/types" |
|
| 7 | 8 |
) |
| 8 | 9 |
|
| 9 | 10 |
var ( |
| ... | ... |
@@ -40,3 +41,19 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
| 40 | 40 |
cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
|
| 41 | 41 |
cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "", usageFn("Users or groups that can access the named pipe"))
|
| 42 | 42 |
} |
| 43 |
+ |
|
| 44 |
+// GetRuntime returns the runtime path and arguments for a given |
|
| 45 |
+// runtime name |
|
| 46 |
+func (config *Config) GetRuntime(name string) *types.Runtime {
|
|
| 47 |
+ return nil |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// GetDefaultRuntimeName returns the current default runtime |
|
| 51 |
+func (config *Config) GetDefaultRuntimeName() string {
|
|
| 52 |
+ return types.DefaultRuntimeName |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+// GetAllRuntimes returns a copy of the runtimes map |
|
| 56 |
+func (config *Config) GetAllRuntimes() map[string]types.Runtime {
|
|
| 57 |
+ return map[string]types.Runtime{}
|
|
| 58 |
+} |
| ... | ... |
@@ -60,6 +60,10 @@ import ( |
| 60 | 60 |
) |
| 61 | 61 |
|
| 62 | 62 |
var ( |
| 63 |
+ // DefaultRuntimeBinary is the default runtime to be used by |
|
| 64 |
+ // containerd if none is specified |
|
| 65 |
+ DefaultRuntimeBinary = "docker-runc" |
|
| 66 |
+ |
|
| 63 | 67 |
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.")
|
| 64 | 68 |
) |
| 65 | 69 |
|
| ... | ... |
@@ -811,10 +815,24 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
|
| 811 | 811 |
// - Cluster discovery (reconfigure and restart). |
| 812 | 812 |
// - Daemon live restore |
| 813 | 813 |
func (daemon *Daemon) Reload(config *Config) error {
|
| 814 |
+ var err error |
|
| 815 |
+ // used to hold reloaded changes |
|
| 816 |
+ attributes := map[string]string{}
|
|
| 817 |
+ |
|
| 818 |
+ // We need defer here to ensure the lock is released as |
|
| 819 |
+ // daemon.SystemInfo() will try to get it too |
|
| 820 |
+ defer func() {
|
|
| 821 |
+ if err == nil {
|
|
| 822 |
+ daemon.LogDaemonEventWithAttributes("reload", attributes)
|
|
| 823 |
+ } |
|
| 824 |
+ }() |
|
| 825 |
+ |
|
| 814 | 826 |
daemon.configStore.reloadLock.Lock() |
| 815 | 827 |
defer daemon.configStore.reloadLock.Unlock() |
| 816 | 828 |
|
| 817 |
- if err := daemon.reloadClusterDiscovery(config); err != nil {
|
|
| 829 |
+ daemon.platformReload(config, &attributes) |
|
| 830 |
+ |
|
| 831 |
+ if err = daemon.reloadClusterDiscovery(config); err != nil {
|
|
| 818 | 832 |
return err |
| 819 | 833 |
} |
| 820 | 834 |
|
| ... | ... |
@@ -859,7 +877,6 @@ func (daemon *Daemon) Reload(config *Config) error {
|
| 859 | 859 |
} |
| 860 | 860 |
|
| 861 | 861 |
// We emit daemon reload event here with updatable configurations |
| 862 |
- attributes := map[string]string{}
|
|
| 863 | 862 |
attributes["debug"] = fmt.Sprintf("%t", daemon.configStore.Debug)
|
| 864 | 863 |
attributes["cluster-store"] = daemon.configStore.ClusterStore |
| 865 | 864 |
if daemon.configStore.ClusterOpts != nil {
|
| ... | ... |
@@ -877,7 +894,6 @@ func (daemon *Daemon) Reload(config *Config) error {
|
| 877 | 877 |
} |
| 878 | 878 |
attributes["max-concurrent-downloads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentDownloads)
|
| 879 | 879 |
attributes["max-concurrent-uploads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentUploads)
|
| 880 |
- daemon.LogDaemonEventWithAttributes("reload", attributes)
|
|
| 881 | 880 |
|
| 882 | 881 |
return nil |
| 883 | 882 |
} |
| ... | ... |
@@ -73,6 +73,10 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
| 73 | 73 |
return warnings, nil |
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
+// platformReload update configuration with platform specific options |
|
| 77 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
|
|
| 78 |
+} |
|
| 79 |
+ |
|
| 76 | 80 |
// verifyDaemonSettings performs validation of daemon config struct |
| 77 | 81 |
func verifyDaemonSettings(config *Config) error {
|
| 78 | 82 |
// checkSystem validates platform-specific requirements |
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
package daemon |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "bytes" |
|
| 6 | 7 |
"fmt" |
| 7 | 8 |
"io/ioutil" |
| 8 | 9 |
"net" |
| ... | ... |
@@ -515,9 +516,42 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
| 515 | 515 |
return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
|
| 516 | 516 |
} |
| 517 | 517 |
} |
| 518 |
+ if hostConfig.Runtime == "" {
|
|
| 519 |
+ hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName() |
|
| 520 |
+ } |
|
| 521 |
+ |
|
| 522 |
+ if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil {
|
|
| 523 |
+ return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime)
|
|
| 524 |
+ } |
|
| 525 |
+ |
|
| 518 | 526 |
return warnings, nil |
| 519 | 527 |
} |
| 520 | 528 |
|
| 529 |
+// platformReload update configuration with platform specific options |
|
| 530 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
|
|
| 531 |
+ if config.IsValueSet("runtimes") {
|
|
| 532 |
+ daemon.configStore.Runtimes = config.Runtimes |
|
| 533 |
+ // Always set the default one |
|
| 534 |
+ daemon.configStore.Runtimes[types.DefaultRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
|
|
| 535 |
+ } |
|
| 536 |
+ |
|
| 537 |
+ if config.DefaultRuntime != "" {
|
|
| 538 |
+ daemon.configStore.DefaultRuntime = config.DefaultRuntime |
|
| 539 |
+ } |
|
| 540 |
+ |
|
| 541 |
+ // Update attributes |
|
| 542 |
+ var runtimeList bytes.Buffer |
|
| 543 |
+ for name, rt := range daemon.configStore.Runtimes {
|
|
| 544 |
+ if runtimeList.Len() > 0 {
|
|
| 545 |
+ runtimeList.WriteRune(' ')
|
|
| 546 |
+ } |
|
| 547 |
+ runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
|
|
| 548 |
+ } |
|
| 549 |
+ |
|
| 550 |
+ (*attributes)["runtimes"] = runtimeList.String() |
|
| 551 |
+ (*attributes)["default-runtime"] = daemon.configStore.DefaultRuntime |
|
| 552 |
+} |
|
| 553 |
+ |
|
| 521 | 554 |
// verifyDaemonSettings performs validation of daemon config struct |
| 522 | 555 |
func verifyDaemonSettings(config *Config) error {
|
| 523 | 556 |
// Check for mutually incompatible config options |
| ... | ... |
@@ -538,6 +572,15 @@ func verifyDaemonSettings(config *Config) error {
|
| 538 | 538 |
return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
|
| 539 | 539 |
} |
| 540 | 540 |
} |
| 541 |
+ |
|
| 542 |
+ if config.DefaultRuntime == "" {
|
|
| 543 |
+ config.DefaultRuntime = types.DefaultRuntimeName |
|
| 544 |
+ } |
|
| 545 |
+ if config.Runtimes == nil {
|
|
| 546 |
+ config.Runtimes = make(map[string]types.Runtime) |
|
| 547 |
+ } |
|
| 548 |
+ config.Runtimes[types.DefaultRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
|
|
| 549 |
+ |
|
| 541 | 550 |
return nil |
| 542 | 551 |
} |
| 543 | 552 |
|
| ... | ... |
@@ -156,6 +156,10 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes. |
| 156 | 156 |
return warnings, nil |
| 157 | 157 |
} |
| 158 | 158 |
|
| 159 |
+// platformReload update configuration with platform specific options |
|
| 160 |
+func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
|
|
| 161 |
+} |
|
| 162 |
+ |
|
| 159 | 163 |
// verifyDaemonSettings performs validation of daemon config struct |
| 160 | 164 |
func verifyDaemonSettings(config *Config) error {
|
| 161 | 165 |
return nil |
| ... | ... |
@@ -131,6 +131,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
| 131 | 131 |
v.CPUCfsQuota = sysInfo.CPUCfsQuota |
| 132 | 132 |
v.CPUShares = sysInfo.CPUShares |
| 133 | 133 |
v.CPUSet = sysInfo.Cpuset |
| 134 |
+ v.Runtimes = daemon.configStore.GetAllRuntimes() |
|
| 135 |
+ v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName() |
|
| 134 | 136 |
} |
| 135 | 137 |
|
| 136 | 138 |
hostname := "" |
| ... | ... |
@@ -132,15 +132,25 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error) |
| 132 | 132 |
return err |
| 133 | 133 |
} |
| 134 | 134 |
|
| 135 |
- if err := daemon.containerd.Create(container.ID, *spec, libcontainerd.WithRestartManager(container.RestartManager(true))); err != nil {
|
|
| 135 |
+ createOptions := []libcontainerd.CreateOption{libcontainerd.WithRestartManager(container.RestartManager(true))}
|
|
| 136 |
+ copts, err := daemon.getLibcontainerdCreateOptions(container) |
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return err |
|
| 139 |
+ } |
|
| 140 |
+ if copts != nil {
|
|
| 141 |
+ createOptions = append(createOptions, *copts...) |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ if err := daemon.containerd.Create(container.ID, *spec, createOptions...); err != nil {
|
|
| 136 | 145 |
errDesc := grpc.ErrorDesc(err) |
| 137 | 146 |
logrus.Errorf("Create container failed with error: %s", errDesc)
|
| 138 | 147 |
// if we receive an internal error from the initial start of a container then lets |
| 139 | 148 |
// return it instead of entering the restart loop |
| 140 | 149 |
// set to 127 for container cmd not found/does not exist) |
| 141 |
- if strings.Contains(errDesc, "executable file not found") || |
|
| 142 |
- strings.Contains(errDesc, "no such file or directory") || |
|
| 143 |
- strings.Contains(errDesc, "system cannot find the file specified") {
|
|
| 150 |
+ if strings.Contains(errDesc, container.Path) && |
|
| 151 |
+ (strings.Contains(errDesc, "executable file not found") || |
|
| 152 |
+ strings.Contains(errDesc, "no such file or directory") || |
|
| 153 |
+ strings.Contains(errDesc, "system cannot find the file specified")) {
|
|
| 144 | 154 |
container.ExitCode = 127 |
| 145 | 155 |
} |
| 146 | 156 |
// set to 126 for container cmd can't be invoked errors |
| 147 | 157 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,20 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/docker/container" |
|
| 6 |
+ "github.com/docker/docker/libcontainerd" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (*[]libcontainerd.CreateOption, error) {
|
|
| 10 |
+ createOptions := []libcontainerd.CreateOption{}
|
|
| 11 |
+ |
|
| 12 |
+ rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime) |
|
| 13 |
+ if rt == nil {
|
|
| 14 |
+ return nil, fmt.Errorf("No such runtime '%s'", container.HostConfig.Runtime)
|
|
| 15 |
+ } |
|
| 16 |
+ createOptions = append(createOptions, libcontainerd.WithRuntime(rt.Path, rt.Args)) |
|
| 17 |
+ |
|
| 18 |
+ return &createOptions, nil |
|
| 19 |
+} |
| 0 | 20 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,10 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/docker/container" |
|
| 4 |
+ "github.com/docker/docker/libcontainerd" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (*[]libcontainerd.CreateOption, error) {
|
|
| 8 |
+ return &[]libcontainerd.CreateOption{}, nil
|
|
| 9 |
+} |
| ... | ... |
@@ -78,6 +78,7 @@ Creates a new container. |
| 78 | 78 |
--privileged Give extended privileges to this container |
| 79 | 79 |
--read-only Mount the container's root filesystem as read only |
| 80 | 80 |
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) |
| 81 |
+ --runtime="" Name of the runtime to be used for that container |
|
| 81 | 82 |
--security-opt=[] Security options |
| 82 | 83 |
--stop-signal="SIGTERM" Signal to stop a container |
| 83 | 84 |
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
| ... | ... |
@@ -60,6 +60,7 @@ weight = -1 |
| 60 | 60 |
-p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file |
| 61 | 61 |
--raw-logs Full timestamps without ANSI coloring |
| 62 | 62 |
--registry-mirror=[] Preferred Docker registry mirror |
| 63 |
+ --add-runtime=[] Register an additional OCI compatible runtime |
|
| 63 | 64 |
-s, --storage-driver="" Storage driver to use |
| 64 | 65 |
--selinux-enabled Enable selinux support |
| 65 | 66 |
--storage-opt=[] Set storage driver options |
| ... | ... |
@@ -572,6 +573,31 @@ The Docker daemon relies on a |
| 572 | 572 |
(invoked via the `containerd` daemon) as its interface to the Linux |
| 573 | 573 |
kernel `namespaces`, `cgroups`, and `SELinux`. |
| 574 | 574 |
|
| 575 |
+Runtimes can be registered with the daemon either via the |
|
| 576 |
+configuration file or using the `--add-runtime` command line argument. |
|
| 577 |
+ |
|
| 578 |
+The following is an example adding 2 runtimes via the configuration: |
|
| 579 |
+```json |
|
| 580 |
+ "default-runtime": "runc", |
|
| 581 |
+ "runtimes": {
|
|
| 582 |
+ "runc": {
|
|
| 583 |
+ "path": "runc" |
|
| 584 |
+ }, |
|
| 585 |
+ "custom": {
|
|
| 586 |
+ "path": "/usr/local/bin/my-runc-replacement", |
|
| 587 |
+ "runtimeArgs": [ |
|
| 588 |
+ "--debug" |
|
| 589 |
+ ] |
|
| 590 |
+ } |
|
| 591 |
+ } |
|
| 592 |
+``` |
|
| 593 |
+ |
|
| 594 |
+This is the same example via the command line: |
|
| 595 |
+ |
|
| 596 |
+ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-runc-replacement |
|
| 597 |
+ |
|
| 598 |
+**Note**: defining runtime arguments via the command line is not supported. |
|
| 599 |
+ |
|
| 575 | 600 |
## Options for the runtime |
| 576 | 601 |
|
| 577 | 602 |
You can configure the runtime using options specified |
| ... | ... |
@@ -1014,7 +1040,19 @@ This is a full example of the allowed configuration options in the file: |
| 1014 | 1014 |
"raw-logs": false, |
| 1015 | 1015 |
"registry-mirrors": [], |
| 1016 | 1016 |
"insecure-registries": [], |
| 1017 |
- "disable-legacy-registry": false |
|
| 1017 |
+ "disable-legacy-registry": false, |
|
| 1018 |
+ "default-runtime": "runc", |
|
| 1019 |
+ "runtimes": {
|
|
| 1020 |
+ "runc": {
|
|
| 1021 |
+ "path": "runc" |
|
| 1022 |
+ }, |
|
| 1023 |
+ "custom": {
|
|
| 1024 |
+ "path": "/usr/local/bin/my-runc-replacement", |
|
| 1025 |
+ "runtimeArgs": [ |
|
| 1026 |
+ "--debug" |
|
| 1027 |
+ ] |
|
| 1028 |
+ } |
|
| 1029 |
+ } |
|
| 1018 | 1030 |
} |
| 1019 | 1031 |
``` |
| 1020 | 1032 |
|
| ... | ... |
@@ -1036,6 +1074,11 @@ The list of currently supported options that can be reconfigured is this: |
| 1036 | 1036 |
- `labels`: it replaces the daemon labels with a new set of labels. |
| 1037 | 1037 |
- `max-concurrent-downloads`: it updates the max concurrent downloads for each pull. |
| 1038 | 1038 |
- `max-concurrent-uploads`: it updates the max concurrent uploads for each push. |
| 1039 |
+- `default-runtime`: it updates the runtime to be used if not is |
|
| 1040 |
+ specified at container creation. It defaults to "default" which is |
|
| 1041 |
+ the runtime shipped with the official docker packages. |
|
| 1042 |
+- `runtimes`: it updates the list of available OCI runtimes that can |
|
| 1043 |
+ be used to run containers |
|
| 1039 | 1044 |
|
| 1040 | 1045 |
Updating and reloading the cluster configurations such as `--cluster-store`, |
| 1041 | 1046 |
`--cluster-advertise` and `--cluster-store-opts` will take effect only if |
| ... | ... |
@@ -89,6 +89,7 @@ parent = "smn_cli" |
| 89 | 89 |
--read-only Mount the container's root filesystem as read only |
| 90 | 90 |
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) |
| 91 | 91 |
--rm Automatically remove the container when it exits |
| 92 |
+ --runtime="" Name of the runtime to be used for that container |
|
| 92 | 93 |
--shm-size=[] Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
| 93 | 94 |
--security-opt=[] Security Options |
| 94 | 95 |
--sig-proxy=true Proxy received signals to the process |
| ... | ... |
@@ -2378,3 +2378,183 @@ func (s *DockerDaemonSuite) TestDaemonDnsOptionsInHostMode(c *check.C) {
|
| 2378 | 2378 |
out, _ := s.d.Cmd("run", "--net=host", "busybox", "cat", "/etc/resolv.conf")
|
| 2379 | 2379 |
c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
|
| 2380 | 2380 |
} |
| 2381 |
+ |
|
| 2382 |
+func (s *DockerDaemonSuite) TestRunWithRuntimeFromConfigFile(c *check.C) {
|
|
| 2383 |
+ conf, err := ioutil.TempFile("", "config-file-")
|
|
| 2384 |
+ c.Assert(err, check.IsNil) |
|
| 2385 |
+ configName := conf.Name() |
|
| 2386 |
+ conf.Close() |
|
| 2387 |
+ defer os.Remove(configName) |
|
| 2388 |
+ |
|
| 2389 |
+ config := ` |
|
| 2390 |
+{
|
|
| 2391 |
+ "runtimes": {
|
|
| 2392 |
+ "oci": {
|
|
| 2393 |
+ "path": "docker-runc" |
|
| 2394 |
+ }, |
|
| 2395 |
+ "vm": {
|
|
| 2396 |
+ "path": "/usr/local/bin/vm-manager", |
|
| 2397 |
+ "runtimeArgs": [ |
|
| 2398 |
+ "--debug" |
|
| 2399 |
+ ] |
|
| 2400 |
+ } |
|
| 2401 |
+ } |
|
| 2402 |
+} |
|
| 2403 |
+` |
|
| 2404 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
| 2405 |
+ err = s.d.Start("--config-file", configName)
|
|
| 2406 |
+ c.Assert(err, check.IsNil) |
|
| 2407 |
+ |
|
| 2408 |
+ // Run with default runtime |
|
| 2409 |
+ out, err := s.d.Cmd("run", "--rm", "busybox", "ls")
|
|
| 2410 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2411 |
+ |
|
| 2412 |
+ // Run with default runtime explicitely |
|
| 2413 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2414 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2415 |
+ |
|
| 2416 |
+ // Run with oci (same path as default) but keep it around |
|
| 2417 |
+ out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls")
|
|
| 2418 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2419 |
+ |
|
| 2420 |
+ // Run with "vm" |
|
| 2421 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls")
|
|
| 2422 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2423 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
| 2424 |
+ |
|
| 2425 |
+ // Reset config to only have the default |
|
| 2426 |
+ config = ` |
|
| 2427 |
+{
|
|
| 2428 |
+ "runtimes": {
|
|
| 2429 |
+ } |
|
| 2430 |
+} |
|
| 2431 |
+` |
|
| 2432 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
| 2433 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
| 2434 |
+ // Give daemon time to reload config |
|
| 2435 |
+ <-time.After(1 * time.Second) |
|
| 2436 |
+ |
|
| 2437 |
+ // Run with default runtime |
|
| 2438 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2439 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2440 |
+ |
|
| 2441 |
+ // Run with "oci" |
|
| 2442 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls")
|
|
| 2443 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2444 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
| 2445 |
+ |
|
| 2446 |
+ // Start previously created container with oci |
|
| 2447 |
+ out, err = s.d.Cmd("start", "oci-runtime-ls")
|
|
| 2448 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2449 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
| 2450 |
+ |
|
| 2451 |
+ // Check that we can't override the default runtime |
|
| 2452 |
+ config = ` |
|
| 2453 |
+{
|
|
| 2454 |
+ "runtimes": {
|
|
| 2455 |
+ "default": {
|
|
| 2456 |
+ "path": "docker-runc" |
|
| 2457 |
+ } |
|
| 2458 |
+ } |
|
| 2459 |
+} |
|
| 2460 |
+` |
|
| 2461 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
| 2462 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
| 2463 |
+ // Give daemon time to reload config |
|
| 2464 |
+ <-time.After(1 * time.Second) |
|
| 2465 |
+ |
|
| 2466 |
+ content, _ := ioutil.ReadFile(s.d.logFile.Name()) |
|
| 2467 |
+ c.Assert(string(content), checker.Contains, `file configuration validation failed (runtime name 'default' is reserved)`) |
|
| 2468 |
+ |
|
| 2469 |
+ // Check that we can select a default runtime |
|
| 2470 |
+ config = ` |
|
| 2471 |
+{
|
|
| 2472 |
+ "default-runtime": "vm", |
|
| 2473 |
+ "runtimes": {
|
|
| 2474 |
+ "oci": {
|
|
| 2475 |
+ "path": "docker-runc" |
|
| 2476 |
+ }, |
|
| 2477 |
+ "vm": {
|
|
| 2478 |
+ "path": "/usr/local/bin/vm-manager", |
|
| 2479 |
+ "runtimeArgs": [ |
|
| 2480 |
+ "--debug" |
|
| 2481 |
+ ] |
|
| 2482 |
+ } |
|
| 2483 |
+ } |
|
| 2484 |
+} |
|
| 2485 |
+` |
|
| 2486 |
+ ioutil.WriteFile(configName, []byte(config), 0644) |
|
| 2487 |
+ syscall.Kill(s.d.cmd.Process.Pid, syscall.SIGHUP) |
|
| 2488 |
+ // Give daemon time to reload config |
|
| 2489 |
+ <-time.After(1 * time.Second) |
|
| 2490 |
+ |
|
| 2491 |
+ out, err = s.d.Cmd("run", "--rm", "busybox", "ls")
|
|
| 2492 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2493 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
| 2494 |
+ |
|
| 2495 |
+ // Run with default runtime explicitely |
|
| 2496 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2497 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2498 |
+} |
|
| 2499 |
+ |
|
| 2500 |
+func (s *DockerDaemonSuite) TestRunWithRuntimeFromCommandLine(c *check.C) {
|
|
| 2501 |
+ err := s.d.Start("--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
|
|
| 2502 |
+ c.Assert(err, check.IsNil) |
|
| 2503 |
+ |
|
| 2504 |
+ // Run with default runtime |
|
| 2505 |
+ out, err := s.d.Cmd("run", "--rm", "busybox", "ls")
|
|
| 2506 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2507 |
+ |
|
| 2508 |
+ // Run with default runtime explicitely |
|
| 2509 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2510 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2511 |
+ |
|
| 2512 |
+ // Run with oci (same path as default) but keep it around |
|
| 2513 |
+ out, err = s.d.Cmd("run", "--name", "oci-runtime-ls", "--runtime=oci", "busybox", "ls")
|
|
| 2514 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2515 |
+ |
|
| 2516 |
+ // Run with "vm" |
|
| 2517 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=vm", "busybox", "ls")
|
|
| 2518 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2519 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
| 2520 |
+ |
|
| 2521 |
+ // Start a daemon without any extra runtimes |
|
| 2522 |
+ s.d.Stop() |
|
| 2523 |
+ err = s.d.Start() |
|
| 2524 |
+ c.Assert(err, check.IsNil) |
|
| 2525 |
+ |
|
| 2526 |
+ // Run with default runtime |
|
| 2527 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2528 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2529 |
+ |
|
| 2530 |
+ // Run with "oci" |
|
| 2531 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=oci", "busybox", "ls")
|
|
| 2532 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2533 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
| 2534 |
+ |
|
| 2535 |
+ // Start previously created container with oci |
|
| 2536 |
+ out, err = s.d.Cmd("start", "oci-runtime-ls")
|
|
| 2537 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2538 |
+ c.Assert(out, checker.Contains, "Unknown runtime specified oci") |
|
| 2539 |
+ |
|
| 2540 |
+ // Check that we can't override the default runtime |
|
| 2541 |
+ s.d.Stop() |
|
| 2542 |
+ err = s.d.Start("--add-runtime", "default=docker-runc")
|
|
| 2543 |
+ c.Assert(err, check.NotNil) |
|
| 2544 |
+ |
|
| 2545 |
+ content, _ := ioutil.ReadFile(s.d.logFile.Name()) |
|
| 2546 |
+ c.Assert(string(content), checker.Contains, `runtime name 'default' is reserved`) |
|
| 2547 |
+ |
|
| 2548 |
+ // Check that we can select a default runtime |
|
| 2549 |
+ s.d.Stop() |
|
| 2550 |
+ err = s.d.Start("--default-runtime=vm", "--add-runtime", "oci=docker-runc", "--add-runtime", "vm=/usr/local/bin/vm-manager")
|
|
| 2551 |
+ c.Assert(err, check.IsNil) |
|
| 2552 |
+ |
|
| 2553 |
+ out, err = s.d.Cmd("run", "--rm", "busybox", "ls")
|
|
| 2554 |
+ c.Assert(err, check.NotNil, check.Commentf(out)) |
|
| 2555 |
+ c.Assert(out, checker.Contains, "/usr/local/bin/vm-manager: no such file or directory") |
|
| 2556 |
+ |
|
| 2557 |
+ // Run with default runtime explicitely |
|
| 2558 |
+ out, err = s.d.Cmd("run", "--rm", "--runtime=default", "busybox", "ls")
|
|
| 2559 |
+ c.Assert(err, check.IsNil, check.Commentf(out)) |
|
| 2560 |
+} |
| ... | ... |
@@ -436,7 +436,8 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
|
| 436 | 436 |
|
| 437 | 437 |
out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c))
|
| 438 | 438 |
c.Assert(err, checker.IsNil) |
| 439 |
- c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, labels=[\"bar=foo\"], max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s)", daemonID, daemonName))
|
|
| 439 |
+ |
|
| 440 |
+ c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=default, labels=[\"bar=foo\"], max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, runtimes=default:{docker-runc []})", daemonID, daemonName))
|
|
| 440 | 441 |
} |
| 441 | 442 |
|
| 442 | 443 |
func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) {
|
| ... | ... |
@@ -34,6 +34,10 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) {
|
| 34 | 34 |
"Network:", |
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 |
+ if DaemonIsLinux.Condition() {
|
|
| 38 |
+ stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: default") |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 37 | 41 |
if utils.ExperimentalBuild() {
|
| 38 | 42 |
stringsToCheck = append(stringsToCheck, "Experimental: true") |
| 39 | 43 |
} |
| ... | ... |
@@ -21,7 +21,27 @@ type container struct {
|
| 21 | 21 |
|
| 22 | 22 |
// Platform specific fields are below here. |
| 23 | 23 |
pauseMonitor |
| 24 |
- oom bool |
|
| 24 |
+ oom bool |
|
| 25 |
+ runtime string |
|
| 26 |
+ runtimeArgs []string |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+type runtime struct {
|
|
| 30 |
+ path string |
|
| 31 |
+ args []string |
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+// WithRuntime sets the runtime to be used for the created container |
|
| 35 |
+func WithRuntime(path string, args []string) CreateOption {
|
|
| 36 |
+ return runtime{path, args}
|
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+func (rt runtime) Apply(p interface{}) error {
|
|
| 40 |
+ if pr, ok := p.(*container); ok {
|
|
| 41 |
+ pr.runtime = rt.path |
|
| 42 |
+ pr.runtimeArgs = rt.args |
|
| 43 |
+ } |
|
| 44 |
+ return nil |
|
| 25 | 45 |
} |
| 26 | 46 |
|
| 27 | 47 |
func (ctr *container) clean() error {
|
| ... | ... |
@@ -84,6 +104,8 @@ func (ctr *container) start() error {
|
| 84 | 84 |
Stderr: ctr.fifo(syscall.Stderr), |
| 85 | 85 |
// check to see if we are running in ramdisk to disable pivot root |
| 86 | 86 |
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
|
| 87 |
+ Runtime: ctr.runtime, |
|
| 88 |
+ RuntimeArgs: ctr.runtimeArgs, |
|
| 87 | 89 |
} |
| 88 | 90 |
ctr.client.appendContainer(ctr) |
| 89 | 91 |
|
| ... | ... |
@@ -50,6 +50,7 @@ type remote struct {
|
| 50 | 50 |
clients []*client |
| 51 | 51 |
eventTsPath string |
| 52 | 52 |
pastEvents map[string]*containerd.Event |
| 53 |
+ runtime string |
|
| 53 | 54 |
runtimeArgs []string |
| 54 | 55 |
daemonWaitCh chan struct{}
|
| 55 | 56 |
liveRestore bool |
| ... | ... |
@@ -366,11 +367,14 @@ func (r *remote) runContainerdDaemon() error {
|
| 366 | 366 |
args := []string{
|
| 367 | 367 |
"-l", fmt.Sprintf("unix://%s", r.rpcAddr),
|
| 368 | 368 |
"--shim", "docker-containerd-shim", |
| 369 |
- "--runtime", "docker-runc", |
|
| 370 | 369 |
"--metrics-interval=0", |
| 371 | 370 |
"--start-timeout", "2m", |
| 372 | 371 |
"--state-dir", filepath.Join(r.stateDir, containerdStateDir), |
| 373 | 372 |
} |
| 373 |
+ if r.runtime != "" {
|
|
| 374 |
+ args = append(args, "--runtime") |
|
| 375 |
+ args = append(args, r.runtime) |
|
| 376 |
+ } |
|
| 374 | 377 |
if r.debugLog {
|
| 375 | 378 |
args = append(args, "--debug") |
| 376 | 379 |
} |
| ... | ... |
@@ -428,6 +432,22 @@ func (a rpcAddr) Apply(r Remote) error {
|
| 428 | 428 |
return fmt.Errorf("WithRemoteAddr option not supported for this remote")
|
| 429 | 429 |
} |
| 430 | 430 |
|
| 431 |
+// WithRuntimePath sets the path of the runtime to be used as the |
|
| 432 |
+// default by containerd |
|
| 433 |
+func WithRuntimePath(rt string) RemoteOption {
|
|
| 434 |
+ return runtimePath(rt) |
|
| 435 |
+} |
|
| 436 |
+ |
|
| 437 |
+type runtimePath string |
|
| 438 |
+ |
|
| 439 |
+func (rt runtimePath) Apply(r Remote) error {
|
|
| 440 |
+ if remote, ok := r.(*remote); ok {
|
|
| 441 |
+ remote.runtime = string(rt) |
|
| 442 |
+ return nil |
|
| 443 |
+ } |
|
| 444 |
+ return fmt.Errorf("WithRuntime option not supported for this remote")
|
|
| 445 |
+} |
|
| 446 |
+ |
|
| 431 | 447 |
// WithRuntimeArgs sets the list of runtime args passed to containerd |
| 432 | 448 |
func WithRuntimeArgs(args []string) RemoteOption {
|
| 433 | 449 |
return runtimeArgs(args) |
| ... | ... |
@@ -101,6 +101,7 @@ type ContainerOptions struct {
|
| 101 | 101 |
flHealthInterval *time.Duration |
| 102 | 102 |
flHealthTimeout *time.Duration |
| 103 | 103 |
flHealthRetries *int |
| 104 |
+ flRuntime *string |
|
| 104 | 105 |
|
| 105 | 106 |
Image string |
| 106 | 107 |
Args []string |
| ... | ... |
@@ -189,6 +190,7 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
|
| 189 | 189 |
flHealthInterval: flags.Duration("health-interval", 0, "Time between running the check"),
|
| 190 | 190 |
flHealthTimeout: flags.Duration("health-timeout", 0, "Maximum time to allow one check to run"),
|
| 191 | 191 |
flHealthRetries: flags.Int("health-retries", 0, "Consecutive failures needed to report unhealthy"),
|
| 192 |
+ flRuntime: flags.String("runtime", "", "Runtime to use for this container"),
|
|
| 192 | 193 |
} |
| 193 | 194 |
|
| 194 | 195 |
flags.VarP(&copts.flAttach, "attach", "a", "Attach to STDIN, STDOUT or STDERR") |
| ... | ... |
@@ -229,7 +231,6 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
|
| 229 | 229 |
// a HostConfig and returns them with the specified command. |
| 230 | 230 |
// If the specified args are not valid, it will return an error. |
| 231 | 231 |
func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
|
| 232 |
- |
|
| 233 | 232 |
var ( |
| 234 | 233 |
attachStdin = copts.flAttach.Get("stdin")
|
| 235 | 234 |
attachStdout = copts.flAttach.Get("stdout")
|
| ... | ... |
@@ -564,6 +565,7 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c |
| 564 | 564 |
Resources: resources, |
| 565 | 565 |
Tmpfs: tmpfs, |
| 566 | 566 |
Sysctls: copts.flSysctls.GetAll(), |
| 567 |
+ Runtime: *copts.flRuntime, |
|
| 567 | 568 |
} |
| 568 | 569 |
|
| 569 | 570 |
// When allocating stdin in attached mode, close stdin at client disconnect |
| 570 | 571 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,73 @@ |
| 0 |
+package opts |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/engine-api/types" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// RuntimeOpt defines a map of Runtimes |
|
| 10 |
+type RuntimeOpt struct {
|
|
| 11 |
+ name string |
|
| 12 |
+ values *map[string]types.Runtime |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+// NewNamedRuntimeOpt creates a new RuntimeOpt |
|
| 16 |
+func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime) *RuntimeOpt {
|
|
| 17 |
+ if ref == nil {
|
|
| 18 |
+ ref = &map[string]types.Runtime{}
|
|
| 19 |
+ } |
|
| 20 |
+ return &RuntimeOpt{name: name, values: ref}
|
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+// Name returns the name of the NamedListOpts in the configuration. |
|
| 24 |
+func (o *RuntimeOpt) Name() string {
|
|
| 25 |
+ return o.name |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+// Set validates and updates the list of Runtimes |
|
| 29 |
+func (o *RuntimeOpt) Set(val string) error {
|
|
| 30 |
+ parts := strings.SplitN(val, "=", 2) |
|
| 31 |
+ if len(parts) != 2 {
|
|
| 32 |
+ return fmt.Errorf("invalid runtime argument: %s", val)
|
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ parts[0] = strings.TrimSpace(parts[0]) |
|
| 36 |
+ parts[1] = strings.TrimSpace(parts[1]) |
|
| 37 |
+ if parts[0] == "" || parts[1] == "" {
|
|
| 38 |
+ return fmt.Errorf("invalid runtime argument: %s", val)
|
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ parts[0] = strings.ToLower(parts[0]) |
|
| 42 |
+ if parts[0] == types.DefaultRuntimeName {
|
|
| 43 |
+ return fmt.Errorf("runtime name 'default' is reserved")
|
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ if _, ok := (*o.values)[parts[0]]; ok {
|
|
| 47 |
+ return fmt.Errorf("runtime '%s' was already defined", parts[0])
|
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+ (*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
|
|
| 51 |
+ |
|
| 52 |
+ return nil |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+// String returns Runtime values as a string. |
|
| 56 |
+func (o *RuntimeOpt) String() string {
|
|
| 57 |
+ var out []string |
|
| 58 |
+ for k := range *o.values {
|
|
| 59 |
+ out = append(out, k) |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ return fmt.Sprintf("%v", out)
|
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+// GetMap returns a map of Runtimes (name: path) |
|
| 66 |
+func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
|
|
| 67 |
+ if o.values != nil {
|
|
| 68 |
+ return *o.values |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ return map[string]types.Runtime{}
|
|
| 72 |
+} |