Browse code

Add OomScoreAdj to configure container oom killer preferences

libcontainer v0.0.4 introduces setting `/proc/self/oom_score_adj` to
better tune oom killing preferences for container process. This patch
simply integrates OomScoreAdj libcontainer's config option and adjust
the cli with this new option.

Signed-off-by: Antonio Murdaca <amurdaca@redhat.com>
Signed-off-by: Antonio Murdaca <runcom@redhat.com>

Antonio Murdaca authored on 2015/10/13 18:26:27
Showing 16 changed files
... ...
@@ -1389,6 +1389,7 @@ _docker_run() {
1389 1389
 		--memory-reservation
1390 1390
 		--name
1391 1391
 		--net
1392
+		--oom-score-adj
1392 1393
 		--pid
1393 1394
 		--publish -p
1394 1395
 		--restart
... ...
@@ -482,6 +482,7 @@ __docker_subcommand() {
482 482
         "($help)--name=[Container name]:name: "
483 483
         "($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
484 484
         "($help)--oom-kill-disable[Disable OOM Killer]"
485
+        "($help)--oom-score-adj[Tune the host's OOM preferences for containers (accepts -1000 to 1000)]"
485 486
         "($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]"
486 487
         "($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports"
487 488
         "($help)--pid=[PID namespace to use]:PID: "
... ...
@@ -345,6 +345,7 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
345 345
 		GIDMapping:         gidMap,
346 346
 		GroupAdd:           c.hostConfig.GroupAdd,
347 347
 		Ipc:                ipc,
348
+		OomScoreAdj:        c.hostConfig.OomScoreAdj,
348 349
 		Pid:                pid,
349 350
 		ReadonlyRootfs:     c.hostConfig.ReadonlyRootfs,
350 351
 		RemappedRoot:       remappedRoot,
... ...
@@ -246,6 +246,9 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
246 246
 		return warnings, fmt.Errorf("Your kernel does not support oom kill disable.")
247 247
 	}
248 248
 
249
+	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
250
+		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
251
+	}
249 252
 	if sysInfo.IPv4ForwardingDisabled {
250 253
 		warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
251 254
 		logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
... ...
@@ -113,6 +113,7 @@ type Command struct {
113 113
 	GIDMapping         []idtools.IDMap   `json:"gidmapping"`
114 114
 	GroupAdd           []string          `json:"group_add"`
115 115
 	Ipc                *Ipc              `json:"ipc"`
116
+	OomScoreAdj        int               `json:"oom_score_adj"`
116 117
 	Pid                *Pid              `json:"pid"`
117 118
 	ReadonlyRootfs     bool              `json:"readonly_rootfs"`
118 119
 	RemappedRoot       *User             `json:"remap_root"`
... ...
@@ -83,6 +83,8 @@ func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks)
83 83
 		return nil, err
84 84
 	}
85 85
 
86
+	container.OomScoreAdj = c.OomScoreAdj
87
+
86 88
 	if container.Readonlyfs {
87 89
 		for i := range container.Mounts {
88 90
 			switch container.Mounts[i].Destination {
... ...
@@ -107,12 +107,11 @@ This section lists each version from latest to oldest.  Each listing includes a
107 107
 * `POST /volumes/create` to create a volume.
108 108
 * `GET /volumes/(name)` get low-level information about a volume.
109 109
 * `DELETE /volumes/(name)`remove a volume with the specified name.
110
-* `VolumeDriver` has been moved from config to hostConfig to make the configuration portable.
111
-* `GET /images/(name)/json` now returns information about tags and digests of the image.
110
+* `VolumeDriver` was moved from `config` to `HostConfig` to make the configuration portable.
111
+* `GET /images/(name)/json` now returns information about an image's `RepoTags` and `RepoDigests`.
112 112
 * The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container.
113 113
 * `GET /containers/(id)/stats` will return networking information respectively for each interface.
114
-* The `hostConfig` option now accepts the field `DnsOptions`, which specifies a
115
-list of DNS options to be used in the container.
114
+* The `HostConfig` option now includes the `DnsOptions` field to configure the container's DNS options.
116 115
 * `POST /build` now optionally takes a serialized map of build-time variables.
117 116
 * `GET /events` now includes a `timenano` field, in addition to the existing `time` field.
118 117
 * `GET /events` now supports filtering by image and container labels.
... ...
@@ -130,6 +129,9 @@ list of DNS options to be used in the container.
130 130
   `NetworkSettings.Gateway`, `NetworkSettings.IPAddress`,
131 131
   `NetworkSettings.IPPrefixLen`, and `NetworkSettings.MacAddress` fields, which
132 132
   are still returned for backward-compatibility, but will be removed in a future version.
133
+* The `HostConfig` option now includes the `OomScoreAdj` field for adjusting the
134
+  badness heuristic. This heuristic selects which processes the OOM killer kills
135
+  under out-of-memory conditions.
133 136
 
134 137
 ### v1.20 API changes
135 138
 
... ...
@@ -217,7 +219,7 @@ container. Previously this was only available when starting a container.
217 217
 [Docker Remote API v1.14](docker_remote_api_v1.14.md) documentation
218 218
 
219 219
 * `DELETE /containers/(id)` when using `force`, the container will be immediately killed with SIGKILL.
220
-* `POST /containers/(id)/start` the `hostConfig` option accepts the field `CapAdd`, which specifies a list of capabilities
220
+* `POST /containers/(id)/start` the `HostConfig` option accepts the field `CapAdd`, which specifies a list of capabilities
221 221
 to add, and the field `CapDrop`, which specifies a list of capabilities to drop.
222 222
 * `POST /images/create` th `fromImage` and `repo` parameters support the
223 223
 `repo:tag` format. Consequently,  the `tag` parameter is now obsolete. Using the
... ...
@@ -190,6 +190,7 @@ Create a container
190 190
              "BlkioWeightDevice": [{}],
191 191
              "MemorySwappiness": 60,
192 192
              "OomKillDisable": false,
193
+             "OomScoreAdj": 500,
193 194
              "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
194 195
              "PublishAllPorts": false,
195 196
              "Privileged": false,
... ...
@@ -243,9 +244,10 @@ Json Parameters:
243 243
 -   **CpusetCpus** - String value containing the `cgroups CpusetCpus` to use.
244 244
 -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
245 245
 -   **BlkioWeight** - Block IO weight (relative weight) accepts a weight value between 10 and 1000.
246
- -   **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of:        `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
246
+-   **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of:        `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
247 247
 -   **MemorySwappiness** - Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
248 248
 -   **OomKillDisable** - Boolean value, whether to disable OOM Killer for the container or not.
249
+-   **OomScoreAdj** - An integer value containing the score given to the container in order to tune OOM killer preferences.
249 250
 -   **AttachStdin** - Boolean value, attaches to `stdin`.
250 251
 -   **AttachStdout** - Boolean value, attaches to `stdout`.
251 252
 -   **AttachStderr** - Boolean value, attaches to `stderr`.
... ...
@@ -416,6 +418,7 @@ Return low-level information on the container `id`
416 416
 			"MemoryReservation": 0,
417 417
 			"KernelMemory": 0,
418 418
 			"OomKillDisable": false,
419
+			"OomScoreAdj": 500,
419 420
 			"NetworkMode": "bridge",
420 421
 			"PortBindings": {},
421 422
 			"Privileged": false,
... ...
@@ -1950,6 +1953,7 @@ Display system-wide information
1950 1950
         "NoProxy": "9.81.1.160",
1951 1951
         "OomKillDisable": true,
1952 1952
         "OSType": "linux",
1953
+        "OomScoreAdj": 500,
1953 1954
         "OperatingSystem": "Boot2Docker",
1954 1955
         "RegistryConfig": {
1955 1956
             "IndexConfigs": {
... ...
@@ -57,6 +57,7 @@ Creates a new container.
57 57
       --name=""                     Assign a name to the container
58 58
       --net="default"               Set the Network mode for the container
59 59
       --oom-kill-disable=false      Whether to disable OOM Killer for the container or not
60
+      --oom-score-adj=0             Tune the host's OOM preferences for containers (accepts -1000 to 1000)
60 61
       -P, --publish-all=false       Publish all exposed ports to random ports
61 62
       -p, --publish=[]              Publish a container's port(s) to the host
62 63
       --pid=""                      PID namespace to use
... ...
@@ -61,6 +61,7 @@ parent = "smn_cli"
61 61
                                     'host': use the host network stack inside the container
62 62
                                     'NETWORK': connects the container to user-created network using `docker network create` command
63 63
       --oom-kill-disable=false      Whether to disable OOM Killer for the container or not
64
+      --oom-score-adj=0             Tune the host's OOM preferences for containers (accepts -1000 to 1000)
64 65
       -P, --publish-all=false       Publish all exposed ports to random ports
65 66
       -p, --publish=[]              Publish a container's port(s) to the host
66 67
       --pid=""                      PID namespace to use
... ...
@@ -1553,3 +1553,34 @@ func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *check.C)
1553 1553
 	expected = "Invalid value 42-3,1-- for cpuset mems.\n"
1554 1554
 	c.Assert(string(body), check.Equals, expected, check.Commentf("Expected output to contain %q, got %q", expected, string(body)))
1555 1555
 }
1556
+
1557
+// check validation is done daemon side and not only in cli
1558
+func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *check.C) {
1559
+	testRequires(c, DaemonIsLinux)
1560
+
1561
+	config := struct {
1562
+		Image       string
1563
+		OomScoreAdj int
1564
+	}{"busybox", 1001}
1565
+	name := "oomscoreadj-over"
1566
+	status, b, err := sockRequest("POST", "/containers/create?name="+name, config)
1567
+	c.Assert(err, check.IsNil)
1568
+	c.Assert(status, check.Equals, http.StatusInternalServerError)
1569
+	expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
1570
+	if !strings.Contains(string(b), expected) {
1571
+		c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
1572
+	}
1573
+
1574
+	config = struct {
1575
+		Image       string
1576
+		OomScoreAdj int
1577
+	}{"busybox", -1001}
1578
+	name = "oomscoreadj-low"
1579
+	status, b, err = sockRequest("POST", "/containers/create?name="+name, config)
1580
+	c.Assert(err, check.IsNil)
1581
+	c.Assert(status, check.Equals, http.StatusInternalServerError)
1582
+	expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
1583
+	if !strings.Contains(string(b), expected) {
1584
+		c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
1585
+	}
1586
+}
... ...
@@ -3761,3 +3761,31 @@ func (s *DockerSuite) TestRunInvalidReference(c *check.C) {
3761 3761
 		c.Fatalf(`Expected "invalid reference format" in output; got: %s`, out)
3762 3762
 	}
3763 3763
 }
3764
+
3765
+func (s *DockerSuite) TestRunWithOomScoreAdj(c *check.C) {
3766
+	testRequires(c, DaemonIsLinux)
3767
+
3768
+	expected := "642"
3769
+	out, _ := dockerCmd(c, "run", "--oom-score-adj", expected, "busybox", "cat", "/proc/self/oom_score_adj")
3770
+	oomScoreAdj := strings.TrimSpace(out)
3771
+	if oomScoreAdj != "642" {
3772
+		c.Fatalf("Expected oom_score_adj set to %q, got %q instead", expected, oomScoreAdj)
3773
+	}
3774
+}
3775
+
3776
+func (s *DockerSuite) TestRunWithOomScoreAdjInvalidRange(c *check.C) {
3777
+	testRequires(c, DaemonIsLinux)
3778
+
3779
+	out, _, err := dockerCmdWithError("run", "--oom-score-adj", "1001", "busybox", "true")
3780
+	c.Assert(err, check.NotNil)
3781
+	expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
3782
+	if !strings.Contains(out, expected) {
3783
+		c.Fatalf("Expected output to contain %q, got %q instead", expected, out)
3784
+	}
3785
+	out, _, err = dockerCmdWithError("run", "--oom-score-adj", "-1001", "busybox", "true")
3786
+	c.Assert(err, check.NotNil)
3787
+	expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
3788
+	if !strings.Contains(out, expected) {
3789
+		c.Fatalf("Expected output to contain %q, got %q instead", expected, out)
3790
+	}
3791
+}
... ...
@@ -46,6 +46,7 @@ docker-create - Create a new container
46 46
 [**--name**[=*NAME*]]
47 47
 [**--net**[=*"bridge"*]]
48 48
 [**--oom-kill-disable**[=*false*]]
49
+[**--oom-score-adj**[=*0*]]
49 50
 [**-P**|**--publish-all**[=*false*]]
50 51
 [**-p**|**--publish**[=*[]*]]
51 52
 [**--pid**[=*[]*]]
... ...
@@ -229,6 +230,9 @@ This value should always larger than **-m**, so you should always use this with
229 229
 **--oom-kill-disable**=*true*|*false*
230 230
 	Whether to disable OOM Killer for the container or not.
231 231
 
232
+**--oom-score-adj**=""
233
+    Tune the host's OOM preferences for containers (accepts -1000 to 1000)
234
+
232 235
 **-P**, **--publish-all**=*true*|*false*
233 236
    Publish all exposed ports to random ports on the host interfaces. The default is *false*.
234 237
 
... ...
@@ -47,6 +47,7 @@ docker-run - Run a command in a new container
47 47
 [**--name**[=*NAME*]]
48 48
 [**--net**[=*"bridge"*]]
49 49
 [**--oom-kill-disable**[=*false*]]
50
+[**--oom-score-adj**[=*0*]]
50 51
 [**-P**|**--publish-all**[=*false*]]
51 52
 [**-p**|**--publish**[=*[]*]]
52 53
 [**--pid**[=*[]*]]
... ...
@@ -341,6 +342,9 @@ and foreground Docker containers.
341 341
 **--oom-kill-disable**=*true*|*false*
342 342
    Whether to disable OOM Killer for the container or not.
343 343
 
344
+**--oom-score-adj**=""
345
+   Tune the host's OOM preferences for containers (accepts -1000 to 1000)
346
+
344 347
 **-P**, **--publish-all**=*true*|*false*
345 348
    Publish all exposed ports to random ports on the host interfaces. The default is *false*.
346 349
 
... ...
@@ -211,6 +211,7 @@ type HostConfig struct {
211 211
 	GroupAdd        []string              // List of additional groups that the container process will run as
212 212
 	IpcMode         IpcMode               // IPC namespace to use for the container
213 213
 	Links           []string              // List of links (in the name:alias form)
214
+	OomScoreAdj     int                   // Container preference for OOM-killing
214 215
 	OomKillDisable  bool                  // Whether to disable OOM Killer or not
215 216
 	PidMode         PidMode               // PID namespace to use for the container
216 217
 	Privileged      bool                  // Is the container in privileged mode
... ...
@@ -79,6 +79,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
79 79
 		flStdin             = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
80 80
 		flTty               = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
81 81
 		flOomKillDisable    = cmd.Bool([]string{"-oom-kill-disable"}, false, "Disable OOM Killer")
82
+		flOomScoreAdj       = cmd.Int([]string{"-oom-score-adj"}, 0, "Tune host's OOM preferences (-1000 to 1000)")
82 83
 		flContainerIDFile   = cmd.String([]string{"-cidfile"}, "", "Write the container ID to the file")
83 84
 		flEntrypoint        = cmd.String([]string{"-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image")
84 85
 		flHostname          = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
... ...
@@ -94,7 +95,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
94 94
 		flCpusetCpus        = cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
95 95
 		flCpusetMems        = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
96 96
 		flBlkioWeight       = cmd.Uint16([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
97
-		flSwappiness        = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tuning container memory swappiness (0 to 100)")
97
+		flSwappiness        = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tune container memory swappiness (0 to 100)")
98 98
 		flNetMode           = cmd.String([]string{"-net"}, "default", "Set the Network for the container")
99 99
 		flMacAddress        = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
100 100
 		flIpcMode           = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
... ...
@@ -369,6 +370,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
369 369
 	hostConfig := &HostConfig{
370 370
 		Binds:           binds,
371 371
 		ContainerIDFile: *flContainerIDFile,
372
+		OomScoreAdj:     *flOomScoreAdj,
372 373
 		OomKillDisable:  *flOomKillDisable,
373 374
 		Privileged:      *flPrivileged,
374 375
 		PortBindings:    portBindings,