From e6cc8fc7139d077051133a1717e1369268713521 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 26 Nov 2014 13:16:53 -0500 Subject: [PATCH] Add support for setting rlimit for contianer Adds a new item to the config struct []*Rlimit Rlimit takes a type (ie, syscall.RLIMIT_NOFILE) and the hard/soft limit (As max/cur) Signed-off-by: Brian Goff --- config.go | 10 ++++++++++ integration/exec_test.go | 21 +++++++++++++++++++++ integration/template_test.go | 9 +++++++++ namespaces/init.go | 14 ++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/config.go b/config.go index 57ea5c69..915e0066 100644 --- a/config.go +++ b/config.go @@ -68,6 +68,10 @@ type Config struct { // RestrictSys will remount /proc/sys, /sys, and mask over sysrq-trigger as well as /proc/irq and // /proc/bus RestrictSys bool `json:"restrict_sys,omitempty"` + + // Rlimits specifies the resource limits, such as max open files, to set in the container + // If Rlimits are not set, the container will inherit rlimits from the parent process + Rlimits []Rlimit `json:"rlimits,omitempty"` } // Routes can be specified to create entries in the route table as the container is started @@ -90,3 +94,9 @@ type Route struct { // The device to set this route up for, for example: eth0 InterfaceName string `json:"interface_name,omitempty"` } + +type Rlimit struct { + Type int `json:"type,omitempty"` + Hard uint64 `json:"hard,omitempty"` + Soft uint64 `json:"soft,omitempty"` +} diff --git a/integration/exec_test.go b/integration/exec_test.go index 261d208e..8f4dae0f 100644 --- a/integration/exec_test.go +++ b/integration/exec_test.go @@ -156,3 +156,24 @@ func TestIPCBadPath(t *testing.T) { t.Fatal("container succeded with bad ipc path") } } + +func TestRlimit(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootFs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + config := newTemplateConfig(rootfs) + out, _, err := runContainer(config, "", "/bin/sh", "-c", "ulimit -n") + if err != nil { + t.Fatal(err) + } + if limit := strings.TrimSpace(out.Stdout.String()); limit != "1024" { + t.Fatalf("expected rlimit to be 1024, got %s", limit) + } +} diff --git a/integration/template_test.go b/integration/template_test.go index 1805eba9..efcf6d5b 100644 --- a/integration/template_test.go +++ b/integration/template_test.go @@ -1,6 +1,8 @@ package integration import ( + "syscall" + "github.com/docker/libcontainer" "github.com/docker/libcontainer/cgroups" "github.com/docker/libcontainer/devices" @@ -60,5 +62,12 @@ func newTemplateConfig(rootfs string) *libcontainer.Config { Gateway: "localhost", }, }, + Rlimits: []libcontainer.Rlimit{ + { + Type: syscall.RLIMIT_NOFILE, + Hard: uint64(1024), + Soft: uint64(1024), + }, + }, } } diff --git a/namespaces/init.go b/namespaces/init.go index 2fa2780e..7c83b137 100644 --- a/namespaces/init.go +++ b/namespaces/init.go @@ -89,6 +89,10 @@ func Init(container *libcontainer.Config, uncleanRootfs, consolePath string, pip return fmt.Errorf("setup route %s", err) } + if err := setupRlimits(container); err != nil { + return fmt.Errorf("setup rlimits %s", err) + } + label.Init() if err := mount.InitializeMountNamespace(rootfs, @@ -238,6 +242,16 @@ func setupRoute(container *libcontainer.Config) error { return nil } +func setupRlimits(container *libcontainer.Config) error { + for _, rlimit := range container.Rlimits { + l := &syscall.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft} + if err := syscall.Setrlimit(rlimit.Type, l); err != nil { + return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err) + } + } + return nil +} + // FinalizeNamespace drops the caps, sets the correct user // and working dir, and closes any leaky file descriptors // before execing the command inside the namespace