From a4a924e1b6c50f0f02460489259d73468a6c282e Mon Sep 17 00:00:00 2001 From: HuKeping Date: Thu, 26 Feb 2015 19:53:55 +0800 Subject: [PATCH] Feature: option for disable OOM killer Add cgroup support for disable OOM killer. Signed-off-by: Hu Keping --- api/types/types.go | 1 + daemon/container.go | 15 +++++++------ daemon/create.go | 5 +++++ daemon/execdriver/driver.go | 15 +++++++------ daemon/execdriver/driver_linux.go | 1 + daemon/execdriver/lxc/lxc_template.go | 3 +++ daemon/info.go | 1 + docs/man/docker-create.1.md | 4 ++++ docs/man/docker-run.1.md | 4 ++++ .../reference/api/docker_remote_api_v1.19.md | 3 +++ docs/sources/reference/commandline/cli.md | 2 ++ docs/sources/reference/run.md | 22 +++++++++++++++++++ pkg/sysinfo/sysinfo.go | 7 ++++++ runconfig/hostconfig.go | 1 + runconfig/parse.go | 4 +++- 15 files changed, 73 insertions(+), 15 deletions(-) diff --git a/api/types/types.go b/api/types/types.go index 7c31065460..2f5e085eb6 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -156,6 +156,7 @@ type Info struct { IPv4Forwarding bool Debug bool NFd int + OomKillDisable bool NGoroutines int SystemTime string ExecutionDriver string diff --git a/daemon/container.go b/daemon/container.go index ef42295344..25254d117e 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -377,13 +377,14 @@ func populateCommand(c *Container, env []string) error { } resources := &execdriver.Resources{ - Memory: c.hostConfig.Memory, - MemorySwap: c.hostConfig.MemorySwap, - CpuShares: c.hostConfig.CpuShares, - CpusetCpus: c.hostConfig.CpusetCpus, - CpusetMems: c.hostConfig.CpusetMems, - CpuQuota: c.hostConfig.CpuQuota, - Rlimits: rlimits, + Memory: c.hostConfig.Memory, + MemorySwap: c.hostConfig.MemorySwap, + CpuShares: c.hostConfig.CpuShares, + CpusetCpus: c.hostConfig.CpusetCpus, + CpusetMems: c.hostConfig.CpusetMems, + CpuQuota: c.hostConfig.CpuQuota, + Rlimits: rlimits, + OomKillDisable: c.hostConfig.OomKillDisable, } processConfig := execdriver.ProcessConfig{ diff --git a/daemon/create.go b/daemon/create.go index d8addd3a99..8cd3030c2a 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -24,6 +24,11 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos return "", warnings, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) } + if !daemon.SystemConfig().OomKillDisable { + hostConfig.OomKillDisable = false + return "", warnings, fmt.Errorf("Your kernel does not support oom kill disable.") + } + container, buildWarnings, err := daemon.Create(config, hostConfig, name) if err != nil { if daemon.Graph().IsNotExist(err, config.Image) { diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index df5901ed02..7827baa266 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -100,13 +100,14 @@ type NetworkInterface struct { // TODO Windows: Factor out ulimit.Rlimit type Resources struct { - Memory int64 `json:"memory"` - MemorySwap int64 `json:"memory_swap"` - CpuShares int64 `json:"cpu_shares"` - CpusetCpus string `json:"cpuset_cpus"` - CpusetMems string `json:"cpuset_mems"` - CpuQuota int64 `json:"cpu_quota"` - Rlimits []*ulimit.Rlimit `json:"rlimits"` + Memory int64 `json:"memory"` + MemorySwap int64 `json:"memory_swap"` + CpuShares int64 `json:"cpu_shares"` + CpusetCpus string `json:"cpuset_cpus"` + CpusetMems string `json:"cpuset_mems"` + CpuQuota int64 `json:"cpu_quota"` + Rlimits []*ulimit.Rlimit `json:"rlimits"` + OomKillDisable bool `json:"oom_kill_disable"` } type ResourceStats struct { diff --git a/daemon/execdriver/driver_linux.go b/daemon/execdriver/driver_linux.go index 1766d64b63..cdaa93af34 100644 --- a/daemon/execdriver/driver_linux.go +++ b/daemon/execdriver/driver_linux.go @@ -54,6 +54,7 @@ func SetupCgroups(container *configs.Config, c *Command) error { container.Cgroups.CpusetCpus = c.Resources.CpusetCpus container.Cgroups.CpusetMems = c.Resources.CpusetMems container.Cgroups.CpuQuota = c.Resources.CpuQuota + container.Cgroups.OomKillDisable = c.Resources.OomKillDisable } return nil diff --git a/daemon/execdriver/lxc/lxc_template.go b/daemon/execdriver/lxc/lxc_template.go index 6b418b26b9..3d7b2b4999 100644 --- a/daemon/execdriver/lxc/lxc_template.go +++ b/daemon/execdriver/lxc/lxc_template.go @@ -118,6 +118,9 @@ lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}} {{if .Resources.CpuQuota}} lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CpuQuota}} {{end}} +{{if .Resources.OomKillDisable}} +lxc.cgroup.memory.oom_control = {{.Resources.OomKillDisable}} +{{end}} {{end}} {{if .LxcConfig}} diff --git a/daemon/info.go b/daemon/info.go index df1c0530cc..e5ccae80aa 100644 --- a/daemon/info.go +++ b/daemon/info.go @@ -68,6 +68,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { IPv4Forwarding: !daemon.SystemConfig().IPv4ForwardingDisabled, Debug: os.Getenv("DEBUG") != "", NFd: fileutils.GetTotalUsedFds(), + OomKillDisable: daemon.SystemConfig().OomKillDisable, NGoroutines: runtime.NumGoroutine(), SystemTime: time.Now().Format(time.RFC3339Nano), ExecutionDriver: daemon.ExecutionDriver().Name(), diff --git a/docs/man/docker-create.1.md b/docs/man/docker-create.1.md index 7aba222b29..d7bdd55789 100644 --- a/docs/man/docker-create.1.md +++ b/docs/man/docker-create.1.md @@ -36,6 +36,7 @@ docker-create - Create a new container [**--mac-address**[=*MAC-ADDRESS*]] [**--name**[=*NAME*]] [**--net**[=*"bridge"*]] +[**--oom-kill-disable**[=*false*]] [**-P**|**--publish-all**[=*false*]] [**-p**|**--publish**[=*[]*]] [**--pid**[=*[]*]] @@ -165,6 +166,9 @@ This value should always larger than **-m**, so you should alway use this with * 'container:': reuses another container network stack 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. +**--oom-kill-disable**=*true*|*false* + Whether to disable OOM Killer for the container or not. + **-P**, **--publish-all**=*true*|*false* Publish all exposed ports to random ports on the host interfaces. The default is *false*. diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index f2ce4b7774..ed331089af 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -37,6 +37,7 @@ docker-run - Run a command in a new container [**--mac-address**[=*MAC-ADDRESS*]] [**--name**[=*NAME*]] [**--net**[=*"bridge"*]] +[**--oom-kill-disable**[=*false*]] [**-P**|**--publish-all**[=*false*]] [**-p**|**--publish**[=*[]*]] [**--pid**[=*[]*]] @@ -285,6 +286,9 @@ and foreground Docker containers. 'container:': reuses another container network stack 'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. +**--oom-kill-disable**=*true*|*false* + Whether to disable OOM Killer for the container or not. + **-P**, **--publish-all**=*true*|*false* Publish all exposed ports to random ports on the host interfaces. The default is *false*. diff --git a/docs/sources/reference/api/docker_remote_api_v1.19.md b/docs/sources/reference/api/docker_remote_api_v1.19.md index cede2e1073..6901c2e6b6 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.19.md +++ b/docs/sources/reference/api/docker_remote_api_v1.19.md @@ -149,6 +149,7 @@ Create a container "CpuShares": 512, "CpusetCpus": "0,1", "CpusetMems": "0,1", + "OomKillDisable": false, "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, "PublishAllPorts": false, "Privileged": false, @@ -194,6 +195,7 @@ Json Parameters: - **Cpuset** - The same as CpusetCpus, but deprecated, please don't use. - **CpusetCpus** - String value containing the cgroups CpusetCpus to use. - **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. +- **OomKillDisable** - Boolean value, whether to disable OOM Killer for the container or not. - **AttachStdin** - Boolean value, attaches to stdin. - **AttachStdout** - Boolean value, attaches to stdout. - **AttachStderr** - Boolean value, attaches to stderr. @@ -354,6 +356,7 @@ Return low-level information on the container `id` "LxcConf": [], "Memory": 0, "MemorySwap": 0, + "OomKillDisable": false, "NetworkMode": "bridge", "PortBindings": {}, "Privileged": false, diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index c69f0a170e..c0c7e9ee58 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -939,6 +939,7 @@ Creates a new container. --mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) --name="" Assign a name to the container --net="bridge" Set the Network mode for the container + --oom-kill-disable=false Whether to disable OOM Killer for the container or not -P, --publish-all=false Publish all exposed ports to random ports -p, --publish=[] Publish a container's port(s) to the host --privileged=false Give extended privileges to this container @@ -1897,6 +1898,7 @@ To remove an image using its digest: --memory-swap="" Total memory (memory + swap), '-1' to disable swap --name="" Assign a name to the container --net="bridge" Set the Network mode for the container + --oom-kill-disable=false Whether to disable OOM Killer for the container or not -P, --publish-all=false Publish all exposed ports to random ports -p, --publish=[] Publish a container's port(s) to the host --pid="" PID namespace to use diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 990faaf6c0..8d97ad7aec 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -476,6 +476,7 @@ container: --cpuset-cpus="": CPUs in which to allow execution (0-3, 0,1) --cpuset-mems="": Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. --cpu-quota=0: Limit the CPU CFS (Completely Fair Scheduler) quota + --oom-kill-disable=true|false: Whether to disable OOM Killer for the container or not. ### Memory constraints @@ -552,6 +553,27 @@ would be 2*300M, so processes can use 300M swap memory as well. We set both memory and swap memory, so the processes in the container can use 300M memory and 700M swap memory. +By default, Docker kills processes in a container if an out-of-memory (OOM) +error occurs. To change this behaviour, use the `--oom-kill-disable` option. +Only disable the OOM killer on containers where you have also set the +`-m/--memory` option. If the `-m` flag is not set, this can result in the host +running out of memory and require killing the host's system processes to free +memory. + +Examples: + +The following example limits the memory to 100M and disables the OOM killer for +this container: + + $ docker run -ti -m 100M --oom-kill-disable ubuntu:14.04 /bin/bash + +The following example, illustrates a dangerous way to use the flag: + + $ docker run -ti --oom-kill-disable ubuntu:14.04 /bin/bash + +The container has unlimited memory which can cause the host to run out memory +and require killing system processes to free memory. + ### CPU share constraint By default, all containers get the same proportion of CPU cycles. This proportion diff --git a/pkg/sysinfo/sysinfo.go b/pkg/sysinfo/sysinfo.go index b6087ff8cd..e679aabd2a 100644 --- a/pkg/sysinfo/sysinfo.go +++ b/pkg/sysinfo/sysinfo.go @@ -18,6 +18,7 @@ type SysInfo struct { CpuCfsQuota bool IPv4ForwardingDisabled bool AppArmor bool + OomKillDisable bool } // New returns a new SysInfo, using the filesystem to detect which features the kernel supports. @@ -36,6 +37,12 @@ func New(quiet bool) *SysInfo { if !sysInfo.SwapLimit && !quiet { logrus.Warn("Your kernel does not support swap memory limit.") } + + _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.oom_control")) + sysInfo.OomKillDisable = err == nil + if !sysInfo.OomKillDisable && !quiet { + logrus.Warnf("Your kernel does not support oom control.") + } } if cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu"); err != nil { diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index 171671b6ef..d634b1ffb9 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -168,6 +168,7 @@ type HostConfig struct { CpusetCpus string // CpusetCpus 0-2, 0,1 CpusetMems string // CpusetMems 0-2, 0,1 CpuQuota int64 + OomKillDisable bool // Whether to disable OOM Killer or not Privileged bool PortBindings nat.PortMap Links []string diff --git a/runconfig/parse.go b/runconfig/parse.go index 4ab4069809..63eeecc5f6 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -53,6 +53,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to random ports") flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached") flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY") + flOomKillDisable = cmd.Bool([]string{"-oom-kill-disable"}, false, "Disable OOM Killer") flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file") flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image") flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name") @@ -63,7 +64,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)") flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)") flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)") - flCpuQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") + flCpuQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS quota") flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container") flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)") flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use") @@ -307,6 +308,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe CpusetCpus: *flCpusetCpus, CpusetMems: *flCpusetMems, CpuQuota: *flCpuQuota, + OomKillDisable: *flOomKillDisable, Privileged: *flPrivileged, PortBindings: portBindings, Links: flLinks.GetAll(),