mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #14579 from hqhq/hq_add_softlimit
Add support for memory reservation
This commit is contained in:
commit
84b53c8d87
18 changed files with 260 additions and 140 deletions
|
@ -1151,6 +1151,7 @@ _docker_run() {
|
||||||
--memory -m
|
--memory -m
|
||||||
--memory-swap
|
--memory-swap
|
||||||
--memory-swappiness
|
--memory-swappiness
|
||||||
|
--memory-reservation
|
||||||
--name
|
--name
|
||||||
--net
|
--net
|
||||||
--pid
|
--pid
|
||||||
|
|
|
@ -272,18 +272,19 @@ func populateCommand(c *Container, env []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
resources := &execdriver.Resources{
|
resources := &execdriver.Resources{
|
||||||
Memory: c.hostConfig.Memory,
|
Memory: c.hostConfig.Memory,
|
||||||
MemorySwap: c.hostConfig.MemorySwap,
|
MemorySwap: c.hostConfig.MemorySwap,
|
||||||
KernelMemory: c.hostConfig.KernelMemory,
|
MemoryReservation: c.hostConfig.MemoryReservation,
|
||||||
CPUShares: c.hostConfig.CPUShares,
|
KernelMemory: c.hostConfig.KernelMemory,
|
||||||
CpusetCpus: c.hostConfig.CpusetCpus,
|
CPUShares: c.hostConfig.CPUShares,
|
||||||
CpusetMems: c.hostConfig.CpusetMems,
|
CpusetCpus: c.hostConfig.CpusetCpus,
|
||||||
CPUPeriod: c.hostConfig.CPUPeriod,
|
CpusetMems: c.hostConfig.CpusetMems,
|
||||||
CPUQuota: c.hostConfig.CPUQuota,
|
CPUPeriod: c.hostConfig.CPUPeriod,
|
||||||
BlkioWeight: c.hostConfig.BlkioWeight,
|
CPUQuota: c.hostConfig.CPUQuota,
|
||||||
Rlimits: rlimits,
|
BlkioWeight: c.hostConfig.BlkioWeight,
|
||||||
OomKillDisable: c.hostConfig.OomKillDisable,
|
Rlimits: rlimits,
|
||||||
MemorySwappiness: -1,
|
OomKillDisable: c.hostConfig.OomKillDisable,
|
||||||
|
MemorySwappiness: -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.hostConfig.MemorySwappiness != nil {
|
if c.hostConfig.MemorySwappiness != nil {
|
||||||
|
|
|
@ -110,6 +110,9 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a
|
||||||
// By default, MemorySwap is set to twice the size of Memory.
|
// By default, MemorySwap is set to twice the size of Memory.
|
||||||
hostConfig.MemorySwap = hostConfig.Memory * 2
|
hostConfig.MemorySwap = hostConfig.Memory * 2
|
||||||
}
|
}
|
||||||
|
if hostConfig.MemoryReservation == 0 && hostConfig.Memory > 0 {
|
||||||
|
hostConfig.MemoryReservation = hostConfig.Memory
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyPlatformContainerSettings performs platform-specific validation of the
|
// verifyPlatformContainerSettings performs platform-specific validation of the
|
||||||
|
@ -154,6 +157,14 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
|
||||||
return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness)
|
return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if hostConfig.MemoryReservation > 0 && !sysInfo.MemoryReservation {
|
||||||
|
warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.")
|
||||||
|
logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.")
|
||||||
|
hostConfig.MemoryReservation = 0
|
||||||
|
}
|
||||||
|
if hostConfig.Memory > 0 && hostConfig.MemoryReservation > 0 && hostConfig.Memory < hostConfig.MemoryReservation {
|
||||||
|
return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.")
|
||||||
|
}
|
||||||
if hostConfig.KernelMemory > 0 && !sysInfo.KernelMemory {
|
if hostConfig.KernelMemory > 0 && !sysInfo.KernelMemory {
|
||||||
warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
|
warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
|
||||||
logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
|
logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
|
||||||
|
|
|
@ -141,18 +141,19 @@ type UTS struct {
|
||||||
// Currently these are all for cgroup configs.
|
// Currently these are all for cgroup configs.
|
||||||
// TODO Windows: Factor out ulimit.Rlimit
|
// TODO Windows: Factor out ulimit.Rlimit
|
||||||
type Resources struct {
|
type Resources struct {
|
||||||
Memory int64 `json:"memory"`
|
Memory int64 `json:"memory"`
|
||||||
MemorySwap int64 `json:"memory_swap"`
|
MemorySwap int64 `json:"memory_swap"`
|
||||||
KernelMemory int64 `json:"kernel_memory"`
|
MemoryReservation int64 `json:"memory_reservation"`
|
||||||
CPUShares int64 `json:"cpu_shares"`
|
KernelMemory int64 `json:"kernel_memory"`
|
||||||
CpusetCpus string `json:"cpuset_cpus"`
|
CPUShares int64 `json:"cpu_shares"`
|
||||||
CpusetMems string `json:"cpuset_mems"`
|
CpusetCpus string `json:"cpuset_cpus"`
|
||||||
CPUPeriod int64 `json:"cpu_period"`
|
CpusetMems string `json:"cpuset_mems"`
|
||||||
CPUQuota int64 `json:"cpu_quota"`
|
CPUPeriod int64 `json:"cpu_period"`
|
||||||
BlkioWeight int64 `json:"blkio_weight"`
|
CPUQuota int64 `json:"cpu_quota"`
|
||||||
Rlimits []*ulimit.Rlimit `json:"rlimits"`
|
BlkioWeight int64 `json:"blkio_weight"`
|
||||||
OomKillDisable bool `json:"oom_kill_disable"`
|
Rlimits []*ulimit.Rlimit `json:"rlimits"`
|
||||||
MemorySwappiness int64 `json:"memory_swappiness"`
|
OomKillDisable bool `json:"oom_kill_disable"`
|
||||||
|
MemorySwappiness int64 `json:"memory_swappiness"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceStats contains information about resource usage by a container.
|
// ResourceStats contains information about resource usage by a container.
|
||||||
|
|
|
@ -64,7 +64,7 @@ func SetupCgroups(container *configs.Config, c *Command) error {
|
||||||
if c.Resources != nil {
|
if c.Resources != nil {
|
||||||
container.Cgroups.CpuShares = c.Resources.CPUShares
|
container.Cgroups.CpuShares = c.Resources.CPUShares
|
||||||
container.Cgroups.Memory = c.Resources.Memory
|
container.Cgroups.Memory = c.Resources.Memory
|
||||||
container.Cgroups.MemoryReservation = c.Resources.Memory
|
container.Cgroups.MemoryReservation = c.Resources.MemoryReservation
|
||||||
container.Cgroups.MemorySwap = c.Resources.MemorySwap
|
container.Cgroups.MemorySwap = c.Resources.MemorySwap
|
||||||
container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
|
container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
|
||||||
container.Cgroups.CpusetMems = c.Resources.CpusetMems
|
container.Cgroups.CpusetMems = c.Resources.CpusetMems
|
||||||
|
|
|
@ -91,11 +91,13 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS
|
||||||
{{if .Resources}}
|
{{if .Resources}}
|
||||||
{{if .Resources.Memory}}
|
{{if .Resources.Memory}}
|
||||||
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
|
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
|
||||||
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}}
|
|
||||||
{{with $memSwap := getMemorySwap .Resources}}
|
{{with $memSwap := getMemorySwap .Resources}}
|
||||||
lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
|
lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if gt .Resources.MemoryReservation 0}}
|
||||||
|
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.MemoryReservation}}
|
||||||
|
{{end}}
|
||||||
{{if gt .Resources.KernelMemory 0}}
|
{{if gt .Resources.KernelMemory 0}}
|
||||||
lxc.cgroup.memory.kmem.limit_in_bytes = {{.Resources.KernelMemory}}
|
lxc.cgroup.memory.kmem.limit_in_bytes = {{.Resources.KernelMemory}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -173,6 +173,7 @@ Create a container
|
||||||
"LxcConf": {"lxc.utsname":"docker"},
|
"LxcConf": {"lxc.utsname":"docker"},
|
||||||
"Memory": 0,
|
"Memory": 0,
|
||||||
"MemorySwap": 0,
|
"MemorySwap": 0,
|
||||||
|
"MemoryReservation": 0,
|
||||||
"KernelMemory": 0,
|
"KernelMemory": 0,
|
||||||
"CpuShares": 512,
|
"CpuShares": 512,
|
||||||
"CpuPeriod": 100000,
|
"CpuPeriod": 100000,
|
||||||
|
@ -223,6 +224,7 @@ Json Parameters:
|
||||||
- **Memory** - Memory limit in bytes.
|
- **Memory** - Memory limit in bytes.
|
||||||
- **MemorySwap** - Total memory limit (memory + swap); set `-1` to disable swap
|
- **MemorySwap** - Total memory limit (memory + swap); set `-1` to disable swap
|
||||||
You must use this with `memory` and make the swap value larger than `memory`.
|
You must use this with `memory` and make the swap value larger than `memory`.
|
||||||
|
- **MemoryReservation** - Memory soft limit in bytes.
|
||||||
- **KernelMemory** - Kernel memory limit in bytes.
|
- **KernelMemory** - Kernel memory limit in bytes.
|
||||||
- **CpuShares** - An integer value containing the container's CPU Shares
|
- **CpuShares** - An integer value containing the container's CPU Shares
|
||||||
(ie. the relative weight vs other containers).
|
(ie. the relative weight vs other containers).
|
||||||
|
@ -398,6 +400,7 @@ Return low-level information on the container `id`
|
||||||
"LxcConf": [],
|
"LxcConf": [],
|
||||||
"Memory": 0,
|
"Memory": 0,
|
||||||
"MemorySwap": 0,
|
"MemorySwap": 0,
|
||||||
|
"MemoryReservation": 0,
|
||||||
"KernelMemory": 0,
|
"KernelMemory": 0,
|
||||||
"OomKillDisable": false,
|
"OomKillDisable": false,
|
||||||
"NetworkMode": "bridge",
|
"NetworkMode": "bridge",
|
||||||
|
|
|
@ -50,6 +50,7 @@ Creates a new container.
|
||||||
--lxc-conf=[] Add custom lxc options
|
--lxc-conf=[] Add custom lxc options
|
||||||
-m, --memory="" Memory limit
|
-m, --memory="" Memory limit
|
||||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||||
|
--memory-reservation="" Memory soft limit
|
||||||
--memory-swap="" Total memory (memory + swap), '-1' to disable swap
|
--memory-swap="" Total memory (memory + swap), '-1' to disable swap
|
||||||
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
|
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
|
||||||
--name="" Assign a name to the container
|
--name="" Assign a name to the container
|
||||||
|
|
|
@ -50,6 +50,7 @@ weight=1
|
||||||
--lxc-conf=[] Add custom lxc options
|
--lxc-conf=[] Add custom lxc options
|
||||||
-m, --memory="" Memory limit
|
-m, --memory="" Memory limit
|
||||||
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||||
|
--memory-reservation="" Memory soft limit
|
||||||
--memory-swap="" Total memory (memory + swap), '-1' to disable swap
|
--memory-swap="" Total memory (memory + swap), '-1' to disable swap
|
||||||
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
|
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
|
||||||
--name="" Assign a name to the container
|
--name="" Assign a name to the container
|
||||||
|
|
|
@ -544,6 +544,7 @@ container:
|
||||||
|----------------------------|---------------------------------------------------------------------------------------------|
|
|----------------------------|---------------------------------------------------------------------------------------------|
|
||||||
| `-m`, `--memory="" ` | Memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
| `-m`, `--memory="" ` | Memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
||||||
| `--memory-swap=""` | Total memory limit (memory + swap, format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
| `--memory-swap=""` | Total memory limit (memory + swap, format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
||||||
|
| `--memory-reservation=""` | Memory soft limit (format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
||||||
| `--kernel-memory=""` | Kernel memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
| `--kernel-memory=""` | Kernel memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g) |
|
||||||
| `-c`, `--cpu-shares=0` | CPU shares (relative weight) |
|
| `-c`, `--cpu-shares=0` | CPU shares (relative weight) |
|
||||||
| `--cpu-period=0` | Limit the CPU CFS (Completely Fair Scheduler) period |
|
| `--cpu-period=0` | Limit the CPU CFS (Completely Fair Scheduler) period |
|
||||||
|
@ -629,6 +630,43 @@ 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
|
We set both memory and swap memory, so the processes in the container can use
|
||||||
300M memory and 700M swap memory.
|
300M memory and 700M swap memory.
|
||||||
|
|
||||||
|
Memory reservation is a kind of memory soft limit that allows for greater
|
||||||
|
sharing of memory. Under normal circumstances, containers can use as much of
|
||||||
|
the memory as needed and are constrained only by the hard limits set with the
|
||||||
|
`-m`/`--memory` option. When memory reservation is set, Docker detects memory
|
||||||
|
contention or low memory and forces containers to restrict their consumption to
|
||||||
|
a reservation limit.
|
||||||
|
|
||||||
|
Always set the memory reservation value below the hard limit, otherwise the hard
|
||||||
|
limit takes precedence. A reservation of 0 is the same as setting no
|
||||||
|
reservation. By default (without reservation set), memory reservation is the
|
||||||
|
same as the hard memory limit.
|
||||||
|
|
||||||
|
Memory reservation is a soft-limit feature and does not guarantee the limit
|
||||||
|
won't be exceeded. Instead, the feature attempts to ensure that, when memory is
|
||||||
|
heavily contended for, memory is allocated based on the reservation hints/setup.
|
||||||
|
|
||||||
|
The following example limits the memory (`-m`) to 500M and sets the memory
|
||||||
|
reservation to 200M.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker run -ti -m 500M --memory-reservation 200M ubuntu:14.04 /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Under this configuration, when the container consumes memory more than 200M and
|
||||||
|
less than 500M, the next system memory reclaim attempts to shrink container
|
||||||
|
memory below 200M.
|
||||||
|
|
||||||
|
The following example set memory reservation to 1G without a hard memory limit.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker run -ti --memory-reservation 1G ubuntu:14.04 /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
The container can use as much memory as it needs. The memory reservation setting
|
||||||
|
ensures the container doesn't consume too much memory for long time, because
|
||||||
|
every memory reclaim shrinks the container's consumption to the reservation.
|
||||||
|
|
||||||
By default, kernel kills processes in a container if an out-of-memory (OOM)
|
By default, kernel kills processes in a container if an out-of-memory (OOM)
|
||||||
error occurs. To change this behaviour, use the `--oom-kill-disable` option.
|
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
|
Only disable the OOM killer on containers where you have also set the
|
||||||
|
|
|
@ -327,6 +327,22 @@ func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestRunWithMemoryReservation(c *check.C) {
|
||||||
|
testRequires(c, memoryReservationSupport)
|
||||||
|
dockerCmd(c, "run", "--memory-reservation", "200M", "busybox", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestRunWithMemoryReservationInvalid(c *check.C) {
|
||||||
|
testRequires(c, memoryLimitSupport)
|
||||||
|
testRequires(c, memoryReservationSupport)
|
||||||
|
out, _, err := dockerCmdWithError("run", "-m", "500M", "--memory-reservation", "800M", "busybox", "true")
|
||||||
|
c.Assert(err, check.NotNil)
|
||||||
|
expected := "Minimum memory limit should be larger than memory reservation limit"
|
||||||
|
if !strings.Contains(strings.TrimSpace(out), expected) {
|
||||||
|
c.Fatalf("run container should fail with invalid memory reservation, output: %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestStopContainerSignal(c *check.C) {
|
func (s *DockerSuite) TestStopContainerSignal(c *check.C) {
|
||||||
out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`)
|
out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`)
|
||||||
containerID := strings.TrimSpace(out)
|
containerID := strings.TrimSpace(out)
|
||||||
|
|
|
@ -45,6 +45,12 @@ var (
|
||||||
},
|
},
|
||||||
"Test requires an environment that supports cgroup memory limit.",
|
"Test requires an environment that supports cgroup memory limit.",
|
||||||
}
|
}
|
||||||
|
memoryReservationSupport = testRequirement{
|
||||||
|
func() bool {
|
||||||
|
return SysInfo.MemoryReservation
|
||||||
|
},
|
||||||
|
"Test requires an environment that supports cgroup memory reservation.",
|
||||||
|
}
|
||||||
swapMemorySupport = testRequirement{
|
swapMemorySupport = testRequirement{
|
||||||
func() bool {
|
func() bool {
|
||||||
return SysInfo.SwapLimit
|
return SysInfo.SwapLimit
|
||||||
|
|
|
@ -40,6 +40,7 @@ docker-create - Create a new container
|
||||||
[**--lxc-conf**[=*[]*]]
|
[**--lxc-conf**[=*[]*]]
|
||||||
[**-m**|**--memory**[=*MEMORY*]]
|
[**-m**|**--memory**[=*MEMORY*]]
|
||||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||||
|
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||||
[**--memory-swap**[=*MEMORY-SWAP*]]
|
[**--memory-swap**[=*MEMORY-SWAP*]]
|
||||||
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
|
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
|
||||||
[**--name**[=*NAME*]]
|
[**--name**[=*NAME*]]
|
||||||
|
@ -196,6 +197,15 @@ system's page size (the value would be very large, that's millions of trillions)
|
||||||
**--mac-address**=""
|
**--mac-address**=""
|
||||||
Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
Container MAC address (e.g. 92:d0:c6:0a:29:33)
|
||||||
|
|
||||||
|
**--memory-reservation**=""
|
||||||
|
Memory soft limit (format: <number>[<unit>], where unit = b, k, m or g)
|
||||||
|
|
||||||
|
After setting memory reservation, when the system detects memory contention
|
||||||
|
or low memory, containers are forced to restrict their consumption to their
|
||||||
|
reservation. So you should always set the value below **--memory**, otherwise the
|
||||||
|
hard limit will take precedence. By default, memory reservation will be the same
|
||||||
|
as memory limit.
|
||||||
|
|
||||||
**--memory-swap**=""
|
**--memory-swap**=""
|
||||||
Total memory limit (memory + swap)
|
Total memory limit (memory + swap)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ docker-run - Run a command in a new container
|
||||||
[**--lxc-conf**[=*[]*]]
|
[**--lxc-conf**[=*[]*]]
|
||||||
[**-m**|**--memory**[=*MEMORY*]]
|
[**-m**|**--memory**[=*MEMORY*]]
|
||||||
[**--mac-address**[=*MAC-ADDRESS*]]
|
[**--mac-address**[=*MAC-ADDRESS*]]
|
||||||
|
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||||
[**--memory-swap**[=*MEMORY-SWAP*]]
|
[**--memory-swap**[=*MEMORY-SWAP*]]
|
||||||
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
|
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
|
||||||
[**--name**[=*NAME*]]
|
[**--name**[=*NAME*]]
|
||||||
|
@ -290,6 +291,15 @@ RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
|
||||||
not limited. The actual limit may be rounded up to a multiple of the operating
|
not limited. The actual limit may be rounded up to a multiple of the operating
|
||||||
system's page size (the value would be very large, that's millions of trillions).
|
system's page size (the value would be very large, that's millions of trillions).
|
||||||
|
|
||||||
|
**--memory-reservation**=""
|
||||||
|
Memory soft limit (format: <number>[<unit>], where unit = b, k, m or g)
|
||||||
|
|
||||||
|
After setting memory reservation, when the system detects memory contention
|
||||||
|
or low memory, containers are forced to restrict their consumption to their
|
||||||
|
reservation. So you should always set the value below **--memory**, otherwise the
|
||||||
|
hard limit will take precedence. By default, memory reservation will be the same
|
||||||
|
as memory limit.
|
||||||
|
|
||||||
**--memory-swap**=""
|
**--memory-swap**=""
|
||||||
Total memory limit (memory + swap)
|
Total memory limit (memory + swap)
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ type cgroupMemInfo struct {
|
||||||
// Whether swap limit is supported or not
|
// Whether swap limit is supported or not
|
||||||
SwapLimit bool
|
SwapLimit bool
|
||||||
|
|
||||||
|
// Whether soft limit is supported or not
|
||||||
|
MemoryReservation bool
|
||||||
|
|
||||||
// Whether OOM killer disalbe is supported or not
|
// Whether OOM killer disalbe is supported or not
|
||||||
OomKillDisable bool
|
OomKillDisable bool
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,10 @@ func checkCgroupMem(quiet bool) cgroupMemInfo {
|
||||||
if !quiet && !swapLimit {
|
if !quiet && !swapLimit {
|
||||||
logrus.Warn("Your kernel does not support swap memory limit.")
|
logrus.Warn("Your kernel does not support swap memory limit.")
|
||||||
}
|
}
|
||||||
|
memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
|
||||||
|
if !quiet && !memoryReservation {
|
||||||
|
logrus.Warn("Your kernel does not support memory reservation.")
|
||||||
|
}
|
||||||
oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
|
oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
|
||||||
if !quiet && !oomKillDisable {
|
if !quiet && !oomKillDisable {
|
||||||
logrus.Warnf("Your kernel does not support oom control.")
|
logrus.Warnf("Your kernel does not support oom control.")
|
||||||
|
@ -63,11 +67,12 @@ func checkCgroupMem(quiet bool) cgroupMemInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
return cgroupMemInfo{
|
return cgroupMemInfo{
|
||||||
MemoryLimit: true,
|
MemoryLimit: true,
|
||||||
SwapLimit: swapLimit,
|
SwapLimit: swapLimit,
|
||||||
OomKillDisable: oomKillDisable,
|
MemoryReservation: memoryReservation,
|
||||||
MemorySwappiness: memorySwappiness,
|
OomKillDisable: oomKillDisable,
|
||||||
KernelMemory: kernelMemory,
|
MemorySwappiness: memorySwappiness,
|
||||||
|
KernelMemory: kernelMemory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -214,45 +214,46 @@ func NewLxcConfig(values []KeyValuePair) *LxcConfig {
|
||||||
// Here, "non-portable" means "dependent of the host we are running on".
|
// Here, "non-portable" means "dependent of the host we are running on".
|
||||||
// Portable information *should* appear in Config.
|
// Portable information *should* appear in Config.
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Binds []string // List of volume bindings for this container
|
Binds []string // List of volume bindings for this container
|
||||||
ContainerIDFile string // File (path) where the containerId is written
|
ContainerIDFile string // File (path) where the containerId is written
|
||||||
LxcConf *LxcConfig // Additional lxc configuration
|
LxcConf *LxcConfig // Additional lxc configuration
|
||||||
Memory int64 // Memory limit (in bytes)
|
Memory int64 // Memory limit (in bytes)
|
||||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||||
KernelMemory int64 // Kernel memory limit (in bytes)
|
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap
|
||||||
CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
|
KernelMemory int64 // Kernel memory limit (in bytes)
|
||||||
CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
|
CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
|
||||||
CpusetCpus string // CpusetCpus 0-2, 0,1
|
CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
|
||||||
CpusetMems string // CpusetMems 0-2, 0,1
|
CpusetCpus string // CpusetCpus 0-2, 0,1
|
||||||
CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota
|
CpusetMems string // CpusetMems 0-2, 0,1
|
||||||
BlkioWeight int64 // Block IO weight (relative weight vs. other containers)
|
CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota
|
||||||
OomKillDisable bool // Whether to disable OOM Killer or not
|
BlkioWeight int64 // Block IO weight (relative weight vs. other containers)
|
||||||
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
OomKillDisable bool // Whether to disable OOM Killer or not
|
||||||
Privileged bool // Is the container in privileged mode
|
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
||||||
PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host
|
Privileged bool // Is the container in privileged mode
|
||||||
Links []string // List of links (in the name:alias form)
|
PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host
|
||||||
PublishAllPorts bool // Should docker publish all exposed port for the container
|
Links []string // List of links (in the name:alias form)
|
||||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
PublishAllPorts bool // Should docker publish all exposed port for the container
|
||||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||||
ExtraHosts []string // List of extra hosts
|
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||||
VolumesFrom []string // List of volumes to take from other container
|
ExtraHosts []string // List of extra hosts
|
||||||
Devices []DeviceMapping // List of devices to map inside the container
|
VolumesFrom []string // List of volumes to take from other container
|
||||||
NetworkMode NetworkMode // Network namespace to use for the container
|
Devices []DeviceMapping // List of devices to map inside the container
|
||||||
IpcMode IpcMode // IPC namespace to use for the container
|
NetworkMode NetworkMode // Network namespace to use for the container
|
||||||
PidMode PidMode // PID namespace to use for the container
|
IpcMode IpcMode // IPC namespace to use for the container
|
||||||
UTSMode UTSMode // UTS namespace to use for the container
|
PidMode PidMode // PID namespace to use for the container
|
||||||
CapAdd *stringutils.StrSlice // List of kernel capabilities to add to the container
|
UTSMode UTSMode // UTS namespace to use for the container
|
||||||
CapDrop *stringutils.StrSlice // List of kernel capabilities to remove from the container
|
CapAdd *stringutils.StrSlice // List of kernel capabilities to add to the container
|
||||||
GroupAdd []string // List of additional groups that the container process will run as
|
CapDrop *stringutils.StrSlice // List of kernel capabilities to remove from the container
|
||||||
RestartPolicy RestartPolicy // Restart policy to be used for the container
|
GroupAdd []string // List of additional groups that the container process will run as
|
||||||
SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux.
|
RestartPolicy RestartPolicy // Restart policy to be used for the container
|
||||||
ReadonlyRootfs bool // Is the container root filesystem in read-only
|
SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux.
|
||||||
Ulimits []*ulimit.Ulimit // List of ulimits to be set in the container
|
ReadonlyRootfs bool // Is the container root filesystem in read-only
|
||||||
LogConfig LogConfig // Configuration of the logs for this container
|
Ulimits []*ulimit.Ulimit // List of ulimits to be set in the container
|
||||||
CgroupParent string // Parent cgroup.
|
LogConfig LogConfig // Configuration of the logs for this container
|
||||||
ConsoleSize [2]int // Initial console size on Windows
|
CgroupParent string // Parent cgroup.
|
||||||
VolumeDriver string // Name of the volume driver used to mount volumes
|
ConsoleSize [2]int // Initial console size on Windows
|
||||||
|
VolumeDriver string // Name of the volume driver used to mount volumes
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeHostConfig creates a HostConfig based on the specified Reader.
|
// DecodeHostConfig creates a HostConfig based on the specified Reader.
|
||||||
|
|
|
@ -64,38 +64,39 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
flLabelsFile = opts.NewListOpts(nil)
|
flLabelsFile = opts.NewListOpts(nil)
|
||||||
flLoggingOpts = opts.NewListOpts(nil)
|
flLoggingOpts = opts.NewListOpts(nil)
|
||||||
|
|
||||||
flNetwork = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
|
flNetwork = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
|
||||||
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
||||||
flPidMode = cmd.String([]string{"-pid"}, "", "PID namespace to use")
|
flPidMode = cmd.String([]string{"-pid"}, "", "PID namespace to use")
|
||||||
flUTSMode = cmd.String([]string{"-uts"}, "", "UTS namespace to use")
|
flUTSMode = cmd.String([]string{"-uts"}, "", "UTS namespace to use")
|
||||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to random ports")
|
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")
|
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")
|
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
|
||||||
flOomKillDisable = cmd.Bool([]string{"-oom-kill-disable"}, false, "Disable OOM Killer")
|
flOomKillDisable = cmd.Bool([]string{"-oom-kill-disable"}, false, "Disable OOM Killer")
|
||||||
flContainerIDFile = cmd.String([]string{"#cidfile", "-cidfile"}, "", "Write the container ID to the file")
|
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")
|
flEntrypoint = cmd.String([]string{"#entrypoint", "-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image")
|
||||||
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
||||||
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit")
|
flMemoryString = cmd.String([]string{"m", "-memory"}, "", "Memory limit")
|
||||||
flMemorySwap = cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
|
flMemoryReservation = cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
|
||||||
flKernelMemory = cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
|
flMemorySwap = cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
|
||||||
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
flKernelMemory = cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
|
||||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
||||||
flCPUShares = cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||||
flCPUPeriod = cmd.Int64([]string{"-cpu-period"}, 0, "Limit CPU CFS (Completely Fair Scheduler) period")
|
flCPUShares = cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||||
flCPUQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
|
flCPUPeriod = cmd.Int64([]string{"-cpu-period"}, 0, "Limit CPU CFS (Completely Fair Scheduler) period")
|
||||||
flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
|
flCPUQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
|
||||||
flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
|
flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
|
||||||
flBlkioWeight = cmd.Int64([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
|
flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
|
||||||
flSwappiness = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tuning container memory swappiness (0 to 100)")
|
flBlkioWeight = cmd.Int64([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
|
||||||
flNetMode = cmd.String([]string{"-net"}, "default", "Set the Network mode for the container")
|
flSwappiness = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tuning container memory swappiness (0 to 100)")
|
||||||
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
|
flNetMode = cmd.String([]string{"-net"}, "default", "Set the Network mode for the container")
|
||||||
flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
|
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
|
||||||
flRestartPolicy = cmd.String([]string{"-restart"}, "no", "Restart policy to apply when a container exits")
|
flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
|
||||||
flReadonlyRootfs = cmd.Bool([]string{"-read-only"}, false, "Mount the container's root filesystem as read only")
|
flRestartPolicy = cmd.String([]string{"-restart"}, "no", "Restart policy to apply when a container exits")
|
||||||
flLoggingDriver = cmd.String([]string{"-log-driver"}, "", "Logging driver for container")
|
flReadonlyRootfs = cmd.Bool([]string{"-read-only"}, false, "Mount the container's root filesystem as read only")
|
||||||
flCgroupParent = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
|
flLoggingDriver = cmd.String([]string{"-log-driver"}, "", "Logging driver for container")
|
||||||
flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container")
|
flCgroupParent = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
|
||||||
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
|
flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container")
|
||||||
|
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR")
|
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR")
|
||||||
|
@ -160,6 +161,14 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MemoryReservation int64
|
||||||
|
if *flMemoryReservation != "" {
|
||||||
|
MemoryReservation, err = units.RAMInBytes(*flMemoryReservation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, cmd, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var memorySwap int64
|
var memorySwap int64
|
||||||
if *flMemorySwap != "" {
|
if *flMemorySwap != "" {
|
||||||
if *flMemorySwap == "-1" {
|
if *flMemorySwap == "-1" {
|
||||||
|
@ -329,44 +338,45 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
}
|
}
|
||||||
|
|
||||||
hostConfig := &HostConfig{
|
hostConfig := &HostConfig{
|
||||||
Binds: binds,
|
Binds: binds,
|
||||||
ContainerIDFile: *flContainerIDFile,
|
ContainerIDFile: *flContainerIDFile,
|
||||||
LxcConf: lxcConf,
|
LxcConf: lxcConf,
|
||||||
Memory: flMemory,
|
Memory: flMemory,
|
||||||
MemorySwap: memorySwap,
|
MemoryReservation: MemoryReservation,
|
||||||
KernelMemory: KernelMemory,
|
MemorySwap: memorySwap,
|
||||||
CPUShares: *flCPUShares,
|
KernelMemory: KernelMemory,
|
||||||
CPUPeriod: *flCPUPeriod,
|
CPUShares: *flCPUShares,
|
||||||
CpusetCpus: *flCpusetCpus,
|
CPUPeriod: *flCPUPeriod,
|
||||||
CpusetMems: *flCpusetMems,
|
CpusetCpus: *flCpusetCpus,
|
||||||
CPUQuota: *flCPUQuota,
|
CpusetMems: *flCpusetMems,
|
||||||
BlkioWeight: *flBlkioWeight,
|
CPUQuota: *flCPUQuota,
|
||||||
OomKillDisable: *flOomKillDisable,
|
BlkioWeight: *flBlkioWeight,
|
||||||
MemorySwappiness: flSwappiness,
|
OomKillDisable: *flOomKillDisable,
|
||||||
Privileged: *flPrivileged,
|
MemorySwappiness: flSwappiness,
|
||||||
PortBindings: portBindings,
|
Privileged: *flPrivileged,
|
||||||
Links: flLinks.GetAll(),
|
PortBindings: portBindings,
|
||||||
PublishAllPorts: *flPublishAll,
|
Links: flLinks.GetAll(),
|
||||||
DNS: flDNS.GetAll(),
|
PublishAllPorts: *flPublishAll,
|
||||||
DNSSearch: flDNSSearch.GetAll(),
|
DNS: flDNS.GetAll(),
|
||||||
DNSOptions: flDNSOptions.GetAll(),
|
DNSSearch: flDNSSearch.GetAll(),
|
||||||
ExtraHosts: flExtraHosts.GetAll(),
|
DNSOptions: flDNSOptions.GetAll(),
|
||||||
VolumesFrom: flVolumesFrom.GetAll(),
|
ExtraHosts: flExtraHosts.GetAll(),
|
||||||
NetworkMode: NetworkMode(*flNetMode),
|
VolumesFrom: flVolumesFrom.GetAll(),
|
||||||
IpcMode: ipcMode,
|
NetworkMode: NetworkMode(*flNetMode),
|
||||||
PidMode: pidMode,
|
IpcMode: ipcMode,
|
||||||
UTSMode: utsMode,
|
PidMode: pidMode,
|
||||||
Devices: deviceMappings,
|
UTSMode: utsMode,
|
||||||
CapAdd: stringutils.NewStrSlice(flCapAdd.GetAll()...),
|
Devices: deviceMappings,
|
||||||
CapDrop: stringutils.NewStrSlice(flCapDrop.GetAll()...),
|
CapAdd: stringutils.NewStrSlice(flCapAdd.GetAll()...),
|
||||||
GroupAdd: flGroupAdd.GetAll(),
|
CapDrop: stringutils.NewStrSlice(flCapDrop.GetAll()...),
|
||||||
RestartPolicy: restartPolicy,
|
GroupAdd: flGroupAdd.GetAll(),
|
||||||
SecurityOpt: flSecurityOpt.GetAll(),
|
RestartPolicy: restartPolicy,
|
||||||
ReadonlyRootfs: *flReadonlyRootfs,
|
SecurityOpt: flSecurityOpt.GetAll(),
|
||||||
Ulimits: flUlimits.GetList(),
|
ReadonlyRootfs: *flReadonlyRootfs,
|
||||||
LogConfig: LogConfig{Type: *flLoggingDriver, Config: loggingOpts},
|
Ulimits: flUlimits.GetList(),
|
||||||
CgroupParent: *flCgroupParent,
|
LogConfig: LogConfig{Type: *flLoggingDriver, Config: loggingOpts},
|
||||||
VolumeDriver: *flVolumeDriver,
|
CgroupParent: *flCgroupParent,
|
||||||
|
VolumeDriver: *flVolumeDriver,
|
||||||
}
|
}
|
||||||
|
|
||||||
applyExperimentalFlags(expFlags, config, hostConfig)
|
applyExperimentalFlags(expFlags, config, hostConfig)
|
||||||
|
|
Loading…
Add table
Reference in a new issue