Adding oom_score_adj as a container config param.

Signed-off-by: Vishnu Kannan <vishnuk@google.com>
This commit is contained in:
Vishnu Kannan 2015-08-26 16:37:24 -07:00
parent b1e7041957
commit cc232c4707
6 changed files with 109 additions and 0 deletions

View File

@ -127,6 +127,12 @@ type Config struct {
// If Rlimits are not set, the container will inherit rlimits from the parent process // If Rlimits are not set, the container will inherit rlimits from the parent process
Rlimits []Rlimit `json:"rlimits"` Rlimits []Rlimit `json:"rlimits"`
// OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores
// for a process. Valid values are between the range [-1000, '1000'], where processes with
// higher scores are preferred for being killed.
// More information about kernel oom score calculation here: https://lwn.net/Articles/317814/
OomScoreAdj int `json:"oom_score_adj"`
// AdditionalGroups specifies the gids that should be added to supplementary groups // AdditionalGroups specifies the gids that should be added to supplementary groups
// in addition to those that the user belongs to. // in addition to those that the user belongs to.
AdditionalGroups []string `json:"additional_groups"` AdditionalGroups []string `json:"additional_groups"`

View File

@ -5,7 +5,9 @@ package libcontainer
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"strconv"
"strings" "strings"
"syscall" "syscall"
@ -238,6 +240,11 @@ func setupRlimits(config *configs.Config) error {
return nil return nil
} }
func setOomScoreAdj(oomScoreAdj int) error {
path := "/proc/self/oom_score_adj"
return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0700)
}
// killCgroupProcesses freezes then iterates over all the processes inside the // killCgroupProcesses freezes then iterates over all the processes inside the
// manager's cgroups sending a SIGKILL to each process then waiting for them to // manager's cgroups sending a SIGKILL to each process then waiting for them to
// exit. // exit.

View File

@ -878,3 +878,45 @@ func TestMountCgroupRW(t *testing.T) {
} }
} }
} }
func TestOomScoreAdj(t *testing.T) {
if testing.Short() {
return
}
root, err := newTestRoot()
ok(t, err)
defer os.RemoveAll(root)
rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)
config := newTemplateConfig(rootfs)
config.OomScoreAdj = 200
factory, err := libcontainer.New(root, libcontainer.Cgroupfs)
ok(t, err)
container, err := factory.Create("test", config)
ok(t, err)
defer container.Destroy()
var stdout bytes.Buffer
pconfig := libcontainer.Process{
Args: []string{"sh", "-c", "cat /proc/self/oom_score_adj"},
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
}
err = container.Start(&pconfig)
ok(t, err)
// Wait for process
waitProcess(&pconfig, t)
outputOomScoreAdj := strings.TrimSpace(string(stdout.Bytes()))
// Check that the oom_score_adj matches the value that was set as part of config.
if outputOomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
t.Fatalf("Expected oom_score_adj %d; got %q", config.OomScoreAdj, outputOomScoreAdj)
}
}

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"io" "io"
"os" "os"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -332,3 +333,49 @@ func TestExecinPassExtraFiles(t *testing.T) {
t.Fatalf("expected second pipe to receive '2', got '%s'", out2) t.Fatalf("expected second pipe to receive '2', got '%s'", out2)
} }
} }
func TestExecInOomScoreAdj(t *testing.T) {
if testing.Short() {
return
}
rootfs, err := newRootfs()
ok(t, err)
defer remove(rootfs)
config := newTemplateConfig(rootfs)
config.OomScoreAdj = 200
container, err := newContainer(config)
ok(t, err)
defer container.Destroy()
stdinR, stdinW, err := os.Pipe()
ok(t, err)
process := &libcontainer.Process{
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
}
err = container.Start(process)
stdinR.Close()
defer stdinW.Close()
ok(t, err)
buffers := newStdBuffers()
ps := &libcontainer.Process{
Args: []string{"/bin/sh", "-c", "cat /proc/self/oom_score_adj"},
Env: standardEnvironment,
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
}
err = container.Start(ps)
ok(t, err)
waitProcess(ps, t)
stdinW.Close()
waitProcess(process, t)
out := buffers.Stdout.String()
if oomScoreAdj := strings.TrimSpace(out); oomScoreAdj != strconv.Itoa(config.OomScoreAdj) {
t.Fatalf("expected oomScoreAdj to be %d, got %s", config.OomScoreAdj, oomScoreAdj)
}
}

View File

@ -21,6 +21,9 @@ func (l *linuxSetnsInit) Init() error {
if err := setupRlimits(l.config.Config); err != nil { if err := setupRlimits(l.config.Config); err != nil {
return err return err
} }
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
return err
}
if l.config.Config.Seccomp != nil { if l.config.Config.Seccomp != nil {
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
return err return err

View File

@ -47,6 +47,10 @@ func (l *linuxStandardInit) Init() error {
if err := setupRlimits(l.config.Config); err != nil { if err := setupRlimits(l.config.Config); err != nil {
return err return err
} }
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
return err
}
label.Init() label.Init()
// InitializeMountNamespace() can be executed only for a new mount namespace // InitializeMountNamespace() can be executed only for a new mount namespace
if l.config.Config.Namespaces.Contains(configs.NEWNS) { if l.config.Config.Namespaces.Contains(configs.NEWNS) {