From f188b9f623e23ee624aca8654bf00f49ee3bae29 Mon Sep 17 00:00:00 2001 From: Victor Marmol Date: Thu, 24 Apr 2014 05:11:43 +0000 Subject: [PATCH] Separating cgroup Memory and MemoryReservation. This will allow for these to be set independently. Keep the current Docker behavior where Memory and MemoryReservation are set to the value of Memory. Docker-DCO-1.1-Signed-off-by: Victor Marmol (github: vmarmol) --- .../execdriver/native/configuration/parse.go | 22 +++++++++++++++---- .../native/configuration/parse_test.go | 18 ++++++++++++++- daemon/execdriver/native/create.go | 1 + pkg/cgroups/cgroups.go | 15 +++++++------ pkg/cgroups/fs/memory.go | 9 +++++--- pkg/cgroups/systemd/apply_systemd.go | 4 ++++ 6 files changed, 54 insertions(+), 15 deletions(-) diff --git a/daemon/execdriver/native/configuration/parse.go b/daemon/execdriver/native/configuration/parse.go index 6d6c643919..c3846af910 100644 --- a/daemon/execdriver/native/configuration/parse.go +++ b/daemon/execdriver/native/configuration/parse.go @@ -21,10 +21,11 @@ var actions = map[string]Action{ "net.join": joinNetNamespace, // join another containers net namespace - "cgroups.cpu_shares": cpuShares, // set the cpu shares - "cgroups.memory": memory, // set the memory limit - "cgroups.memory_swap": memorySwap, // set the memory swap limit - "cgroups.cpuset.cpus": cpusetCpus, // set the cpus used + "cgroups.cpu_shares": cpuShares, // set the cpu shares + "cgroups.memory": memory, // set the memory limit + "cgroups.memory_reservation": memoryReservation, // set the memory reservation + "cgroups.memory_swap": memorySwap, // set the memory swap limit + "cgroups.cpuset.cpus": cpusetCpus, // set the cpus used "apparmor_profile": apparmorProfile, // set the apparmor profile to apply @@ -70,6 +71,19 @@ func memory(container *libcontainer.Container, context interface{}, value string return nil } +func memoryReservation(container *libcontainer.Container, context interface{}, value string) error { + if container.Cgroups == nil { + return fmt.Errorf("cannot set cgroups when they are disabled") + } + + v, err := utils.RAMInBytes(value) + if err != nil { + return err + } + container.Cgroups.MemoryReservation = v + return nil +} + func memorySwap(container *libcontainer.Container, context interface{}, value string) error { if container.Cgroups == nil { return fmt.Errorf("cannot set cgroups when they are disabled") diff --git a/daemon/execdriver/native/configuration/parse_test.go b/daemon/execdriver/native/configuration/parse_test.go index 9034867b7b..c28176f2ef 100644 --- a/daemon/execdriver/native/configuration/parse_test.go +++ b/daemon/execdriver/native/configuration/parse_test.go @@ -93,7 +93,7 @@ func TestCpuShares(t *testing.T) { } } -func TestCgroupMemory(t *testing.T) { +func TestMemory(t *testing.T) { var ( container = template.New() opts = []string{ @@ -109,6 +109,22 @@ func TestCgroupMemory(t *testing.T) { } } +func TestMemoryReservation(t *testing.T) { + var ( + container = template.New() + opts = []string{ + "cgroups.memory_reservation=500m", + } + ) + if err := ParseConfiguration(container, nil, opts); err != nil { + t.Fatal(err) + } + + if expected := int64(500 * 1024 * 1024); container.Cgroups.MemoryReservation != expected { + t.Fatalf("expected memory reservation %d got %d", expected, container.Cgroups.MemoryReservation) + } +} + func TestAddCap(t *testing.T) { var ( container = template.New() diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index ef17ce7042..334a97ad4b 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -91,6 +91,7 @@ func (d *driver) setupCgroups(container *libcontainer.Container, c *execdriver.C if c.Resources != nil { container.Cgroups.CpuShares = c.Resources.CpuShares container.Cgroups.Memory = c.Resources.Memory + container.Cgroups.MemoryReservation = c.Resources.Memory container.Cgroups.MemorySwap = c.Resources.MemorySwap } return nil diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index 9a498609b5..81e3eb551a 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -12,13 +12,14 @@ type Cgroup struct { Name string `json:"name,omitempty"` Parent string `json:"parent,omitempty"` - DeviceAccess bool `json:"device_access,omitempty"` // name of parent cgroup or slice - Memory int64 `json:"memory,omitempty"` // Memory limit (in bytes) - MemorySwap int64 `json:"memory_swap,omitempty"` // Total memory usage (memory + swap); set `-1' to disable swap - CpuShares int64 `json:"cpu_shares,omitempty"` // CPU shares (relative weight vs. other containers) - CpuQuota int64 `json:"cpu_quota,omitempty"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period. - CpuPeriod int64 `json:"cpu_period,omitempty"` // CPU period to be used for hardcapping (in usecs). 0 to use system default. - CpusetCpus string `json:"cpuset_cpus,omitempty"` // CPU to use + DeviceAccess bool `json:"device_access,omitempty"` // name of parent cgroup or slice + Memory int64 `json:"memory,omitempty"` // Memory limit (in bytes) + MemoryReservation int64 `json:"memory_reservation,omitempty"` // Memory reservation or soft_limit (in bytes) + MemorySwap int64 `json:"memory_swap,omitempty"` // Total memory usage (memory + swap); set `-1' to disable swap + CpuShares int64 `json:"cpu_shares,omitempty"` // CPU shares (relative weight vs. other containers) + CpuQuota int64 `json:"cpu_quota,omitempty"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period. + CpuPeriod int64 `json:"cpu_period,omitempty"` // CPU period to be used for hardcapping (in usecs). 0 to use system default. + CpusetCpus string `json:"cpuset_cpus,omitempty"` // CPU to use UnitProperties [][2]string `json:"unit_properties,omitempty"` // systemd unit properties } diff --git a/pkg/cgroups/fs/memory.go b/pkg/cgroups/fs/memory.go index cf4bf5ab73..5315291197 100644 --- a/pkg/cgroups/fs/memory.go +++ b/pkg/cgroups/fs/memory.go @@ -13,7 +13,7 @@ type memoryGroup struct { func (s *memoryGroup) Set(d *data) error { dir, err := d.join("memory") // only return an error for memory if it was not specified - if err != nil && (d.c.Memory != 0 || d.c.MemorySwap != 0) { + if err != nil && (d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0) { return err } defer func() { @@ -22,12 +22,15 @@ func (s *memoryGroup) Set(d *data) error { } }() - if d.c.Memory != 0 || d.c.MemorySwap != 0 { + // Only set values if some config was specified. + if d.c.Memory != 0 || d.c.MemoryReservation != 0 || d.c.MemorySwap != 0 { if d.c.Memory != 0 { if err := writeFile(dir, "memory.limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil { return err } - if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.Memory, 10)); err != nil { + } + if d.c.MemoryReservation != 0 { + if err := writeFile(dir, "memory.soft_limit_in_bytes", strconv.FormatInt(d.c.MemoryReservation, 10)); err != nil { return err } } diff --git a/pkg/cgroups/systemd/apply_systemd.go b/pkg/cgroups/systemd/apply_systemd.go index 7c26080d6e..e1246f6e70 100644 --- a/pkg/cgroups/systemd/apply_systemd.go +++ b/pkg/cgroups/systemd/apply_systemd.go @@ -121,6 +121,10 @@ func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) { properties = append(properties, systemd1.Property{"MemoryLimit", dbus.MakeVariant(uint64(c.Memory))}) } + if c.MemoryReservation != 0 { + properties = append(properties, + systemd1.Property{"MemorySoftLimit", dbus.MakeVariant(uint64(c.MemoryReservation))}) + } // TODO: MemorySwap not available in systemd if c.CpuShares != 0 {