Browse code

Add --oom-score-adjust to daemon

This adds an `--oom-score-adjust` flag to the daemon so that the value
provided can be set for the docker daemon's process. The default value
for the flag is -500. This will allow the docker daemon to have a
less chance of being killed before containers do. The default value for
processes is 0 with a min/max of -1000/1000.

-500 is a good middle ground because it is less than the default for
most processes and still not -1000 which basically means never kill this
process in an OOM condition on the host machine. The only processes on
my machine that have a score less than -500 are dbus at -900 and sshd
and xfce( my window manager ) at -1000. I don't think docker should be
set lower, by default, than dbus or sshd so that is why I chose -500.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
(cherry picked from commit a894aec8d81de5484152a76d76b80809df9edd71)
Signed-off-by: Tibor Vass <tibor@docker.com>

Michael Crosby authored on 2016/07/12 07:26:23
Showing 8 changed files
... ...
@@ -61,6 +61,7 @@ func (cli *DaemonCli) setupConfigReloadTrap() {
61 61
 func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption {
62 62
 	opts := []libcontainerd.RemoteOption{
63 63
 		libcontainerd.WithDebugLog(cli.Config.Debug),
64
+		libcontainerd.WithOOMScore(cli.Config.OOMScoreAdjust),
64 65
 	}
65 66
 	if cli.Config.ContainerdAddr != "" {
66 67
 		opts = append(opts, libcontainerd.WithRemoteAddr(cli.Config.ContainerdAddr))
... ...
@@ -34,6 +34,7 @@ type Config struct {
34 34
 	Ulimits              map[string]*units.Ulimit `json:"default-ulimits,omitempty"`
35 35
 	Runtimes             map[string]types.Runtime `json:"runtimes,omitempty"`
36 36
 	DefaultRuntime       string                   `json:"default-runtime,omitempty"`
37
+	OOMScoreAdjust       int                      `json:"oom-score-adjust,omitempty"`
37 38
 }
38 39
 
39 40
 // bridgeConfig stores all the bridge driver specific
... ...
@@ -90,6 +91,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
90 90
 	config.Runtimes = make(map[string]types.Runtime)
91 91
 	cmd.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), []string{"-add-runtime"}, usageFn("Register an additional OCI compatible runtime"))
92 92
 	cmd.StringVar(&config.DefaultRuntime, []string{"-default-runtime"}, stockRuntimeName, usageFn("Default OCI runtime to be used"))
93
+	cmd.IntVar(&config.OOMScoreAdjust, []string{"-oom-score-adjust"}, -500, usageFn("Set the oom_score_adj for the daemon"))
93 94
 
94 95
 	config.attachExperimentalFlags(cmd, usageFn)
95 96
 }
... ...
@@ -432,7 +432,11 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
432 432
 		}
433 433
 	}
434 434
 
435
-	if err = setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil {
435
+	if err := setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil {
436
+		return nil, err
437
+	}
438
+
439
+	if err := setupDaemonProcess(config); err != nil {
436 440
 		return nil, err
437 441
 	}
438 442
 
... ...
@@ -161,3 +161,7 @@ func (daemon *Daemon) setDefaultIsolation() error {
161 161
 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
162 162
 	return types.RootFS{}
163 163
 }
164
+
165
+func setupDaemonProcess(config *Config) error {
166
+	return nil
167
+}
... ...
@@ -1146,3 +1146,19 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
1146 1146
 		Layers: layers,
1147 1147
 	}
1148 1148
 }
1149
+
1150
+// setupDaemonProcess sets various settings for the daemon's process
1151
+func setupDaemonProcess(config *Config) error {
1152
+	// setup the daemons oom_score_adj
1153
+	return setupOOMScoreAdj(config.OOMScoreAdjust)
1154
+}
1155
+
1156
+func setupOOMScoreAdj(score int) error {
1157
+	f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
1158
+	if err != nil {
1159
+		return err
1160
+	}
1161
+	_, err = f.WriteString(strconv.Itoa(score))
1162
+	f.Close()
1163
+	return err
1164
+}
... ...
@@ -519,3 +519,7 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
519 519
 		BaseLayer: rootfs.BaseLayer,
520 520
 	}
521 521
 }
522
+
523
+func setupDaemonProcess(config *Config) error {
524
+	return nil
525
+}
... ...
@@ -54,9 +54,10 @@ weight = -1
54 54
       --label=[]                             Set key=value labels to the daemon
55 55
       --log-driver="json-file"               Default driver for container logs
56 56
       --log-opt=[]                           Log driver specific options
57
-      --mtu=0                                Set the containers network MTU
58 57
       --max-concurrent-downloads=3           Set the max concurrent downloads for each pull
59 58
       --max-concurrent-uploads=5             Set the max concurrent uploads for each push
59
+      --mtu=0                                Set the containers network MTU
60
+      --oom-score-adjust=-500                Set the oom_score_adj for the daemon
60 61
       --disable-legacy-registry              Do not contact legacy registries
61 62
       -p, --pidfile="/var/run/docker.pid"    Path to use for daemon PID file
62 63
       --raw-logs                             Full timestamps without ANSI coloring
... ...
@@ -1057,6 +1058,7 @@ This is a full example of the allowed configuration options on Linux:
1057 1057
 	"insecure-registries": [],
1058 1058
 	"disable-legacy-registry": false,
1059 1059
 	"default-runtime": "runc",
1060
+	"oom-score-adjust": -500,
1060 1061
 	"runtimes": {
1061 1062
 		"runc": {
1062 1063
 			"path": "runc"
... ...
@@ -54,6 +54,7 @@ type remote struct {
54 54
 	runtimeArgs   []string
55 55
 	daemonWaitCh  chan struct{}
56 56
 	liveRestore   bool
57
+	oomScore      int
57 58
 }
58 59
 
59 60
 // New creates a fresh instance of libcontainerd remote.
... ...
@@ -402,7 +403,10 @@ func (r *remote) runContainerdDaemon() error {
402 402
 		return err
403 403
 	}
404 404
 	logrus.Infof("New containerd process, pid: %d", cmd.Process.Pid)
405
-
405
+	if err := setOOMScore(cmd.Process.Pid, r.oomScore); err != nil {
406
+		utils.KillProcess(cmd.Process.Pid)
407
+		return err
408
+	}
406 409
 	if _, err := f.WriteString(fmt.Sprintf("%d", cmd.Process.Pid)); err != nil {
407 410
 		utils.KillProcess(cmd.Process.Pid)
408 411
 		return err
... ...
@@ -417,6 +421,16 @@ func (r *remote) runContainerdDaemon() error {
417 417
 	return nil
418 418
 }
419 419
 
420
+func setOOMScore(pid, score int) error {
421
+	f, err := os.OpenFile(fmt.Sprintf("/proc/%d/oom_score_adj", pid), os.O_WRONLY, 0)
422
+	if err != nil {
423
+		return err
424
+	}
425
+	_, err = f.WriteString(strconv.Itoa(score))
426
+	f.Close()
427
+	return err
428
+}
429
+
420 430
 // WithRemoteAddr sets the external containerd socket to connect to.
421 431
 func WithRemoteAddr(addr string) RemoteOption {
422 432
 	return rpcAddr(addr)
... ...
@@ -510,3 +524,18 @@ func (l liveRestore) Apply(r Remote) error {
510 510
 	}
511 511
 	return fmt.Errorf("WithLiveRestore option not supported for this remote")
512 512
 }
513
+
514
+// WithOOMScore defines the oom_score_adj to set for the containerd process.
515
+func WithOOMScore(score int) RemoteOption {
516
+	return oomScore(score)
517
+}
518
+
519
+type oomScore int
520
+
521
+func (o oomScore) Apply(r Remote) error {
522
+	if remote, ok := r.(*remote); ok {
523
+		remote.oomScore = int(o)
524
+		return nil
525
+	}
526
+	return fmt.Errorf("WithOOMScore option not supported for this remote")
527
+}