diff --git a/cmd/dockerd/daemon_unix.go b/cmd/dockerd/daemon_unix.go index 3e197c498f..114e9426fd 100644 --- a/cmd/dockerd/daemon_unix.go +++ b/cmd/dockerd/daemon_unix.go @@ -61,6 +61,7 @@ func (cli *DaemonCli) setupConfigReloadTrap() { func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption { opts := []libcontainerd.RemoteOption{ libcontainerd.WithDebugLog(cli.Config.Debug), + libcontainerd.WithOOMScore(cli.Config.OOMScoreAdjust), } if cli.Config.ContainerdAddr != "" { opts = append(opts, libcontainerd.WithRemoteAddr(cli.Config.ContainerdAddr)) diff --git a/daemon/config_unix.go b/daemon/config_unix.go index deaf8c6732..26beaf4f32 100644 --- a/daemon/config_unix.go +++ b/daemon/config_unix.go @@ -34,6 +34,7 @@ type Config struct { Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"` Runtimes map[string]types.Runtime `json:"runtimes,omitempty"` DefaultRuntime string `json:"default-runtime,omitempty"` + OOMScoreAdjust int `json:"oom-score-adjust,omitempty"` } // bridgeConfig stores all the bridge driver specific @@ -90,6 +91,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin config.Runtimes = make(map[string]types.Runtime) cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime")) cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, stockRuntimeName, usageFn("Default OCI runtime to be used")) + cmd.IntVar(&config.OOMScoreAdjust, []string{"-oom-score-adjust"}, -500, usageFn("Set the oom_score_adj for the daemon")) config.attachExperimentalFlags(cmd, usageFn) } diff --git a/daemon/daemon.go b/daemon/daemon.go index bdfffd729c..33efc2be55 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -434,7 +434,11 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot } } - if err = setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil { + if err := setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil { + return nil, err + } + + if err := setupDaemonProcess(config); err != nil { return nil, err } diff --git a/daemon/daemon_solaris.go b/daemon/daemon_solaris.go index 48fed719fa..5c49af56c9 100644 --- a/daemon/daemon_solaris.go +++ b/daemon/daemon_solaris.go @@ -161,3 +161,7 @@ func (daemon *Daemon) setDefaultIsolation() error { func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { return types.RootFS{} } + +func setupDaemonProcess(config *Config) error { + return nil +} diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index a38a046b7a..15015b8e7d 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -1139,3 +1139,19 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { Layers: layers, } } + +// setupDaemonProcess sets various settings for the daemon's process +func setupDaemonProcess(config *Config) error { + // setup the daemons oom_score_adj + return setupOOMScoreAdj(config.OOMScoreAdjust) +} + +func setupOOMScoreAdj(score int) error { + f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0) + if err != nil { + return err + } + _, err = f.WriteString(strconv.Itoa(score)) + f.Close() + return err +} diff --git a/daemon/daemon_windows.go b/daemon/daemon_windows.go index 8e0fb52183..f6efe54784 100644 --- a/daemon/daemon_windows.go +++ b/daemon/daemon_windows.go @@ -431,3 +431,7 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS { BaseLayer: rootfs.BaseLayer, } } + +func setupDaemonProcess(config *Config) error { + return nil +} diff --git a/docs/reference/commandline/dockerd.md b/docs/reference/commandline/dockerd.md index 8c53fd02c3..61b11d4ca7 100644 --- a/docs/reference/commandline/dockerd.md +++ b/docs/reference/commandline/dockerd.md @@ -54,9 +54,10 @@ weight = -1 --label=[] Set key=value labels to the daemon --log-driver="json-file" Default driver for container logs --log-opt=[] Log driver specific options - --mtu=0 Set the containers network MTU --max-concurrent-downloads=3 Set the max concurrent downloads for each pull --max-concurrent-uploads=5 Set the max concurrent uploads for each push + --mtu=0 Set the containers network MTU + --oom-score-adjust=-500 Set the oom_score_adj for the daemon --disable-legacy-registry Do not contact legacy registries -p, --pidfile="/var/run/docker.pid" Path to use for daemon PID file --raw-logs Full timestamps without ANSI coloring @@ -1057,6 +1058,7 @@ This is a full example of the allowed configuration options on Linux: "insecure-registries": [], "disable-legacy-registry": false, "default-runtime": "runc", + "oom-score-adjust": -500, "runtimes": { "runc": { "path": "runc" diff --git a/libcontainerd/remote_linux.go b/libcontainerd/remote_linux.go index 5f4e812cfb..0e226dffbe 100644 --- a/libcontainerd/remote_linux.go +++ b/libcontainerd/remote_linux.go @@ -54,6 +54,7 @@ type remote struct { runtimeArgs []string daemonWaitCh chan struct{} liveRestore bool + oomScore int } // New creates a fresh instance of libcontainerd remote. @@ -402,7 +403,10 @@ func (r *remote) runContainerdDaemon() error { return err } logrus.Infof("New containerd process, pid: %d", cmd.Process.Pid) - + if err := setOOMScore(cmd.Process.Pid, r.oomScore); err != nil { + utils.KillProcess(cmd.Process.Pid) + return err + } if _, err := f.WriteString(fmt.Sprintf("%d", cmd.Process.Pid)); err != nil { utils.KillProcess(cmd.Process.Pid) return err @@ -417,6 +421,16 @@ func (r *remote) runContainerdDaemon() error { return nil } +func setOOMScore(pid, score int) error { + f, err := os.OpenFile(fmt.Sprintf("/proc/%d/oom_score_adj", pid), os.O_WRONLY, 0) + if err != nil { + return err + } + _, err = f.WriteString(strconv.Itoa(score)) + f.Close() + return err +} + // WithRemoteAddr sets the external containerd socket to connect to. func WithRemoteAddr(addr string) RemoteOption { return rpcAddr(addr) @@ -510,3 +524,18 @@ func (l liveRestore) Apply(r Remote) error { } return fmt.Errorf("WithLiveRestore option not supported for this remote") } + +// WithOOMScore defines the oom_score_adj to set for the containerd process. +func WithOOMScore(score int) RemoteOption { + return oomScore(score) +} + +type oomScore int + +func (o oomScore) Apply(r Remote) error { + if remote, ok := r.(*remote); ok { + remote.oomScore = int(o) + return nil + } + return fmt.Errorf("WithOOMScore option not supported for this remote") +}