Skip to content

Commit

Permalink
Make POD container last OOM victim.
Browse files Browse the repository at this point in the history
Setting the oom_score_adj of the PID of the POD container to -100 which is less
than the default of 0. This ensures that this PID is the last OOM victim
chosen by the kernel.

Fixes kubernetes#3067.
  • Loading branch information
vmarmol committed Feb 20, 2015
1 parent 2d1a8d0 commit 8649628
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
19 changes: 18 additions & 1 deletion pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ const minShares = 2
const sharesPerCPU = 1024
const milliCPUToCPU = 1000

// The oom_score_adj of the POD infrastructure container. The default is 0, so
// any value below that makes it *less* likely to get OOM killed.
const podOomScoreAdj = -100

// SyncHandler is an interface implemented by Kubelet, for testability
type SyncHandler interface {
SyncPods([]api.BoundPod) error
Expand Down Expand Up @@ -938,7 +942,20 @@ func (kl *Kubelet) createPodInfraContainer(pod *api.BoundPod) (dockertools.Docke
if ref != nil {
record.Eventf(ref, "pulled", "Successfully pulled image %q", container.Image)
}
return kl.runContainer(pod, container, nil, "", "")
id, err := kl.runContainer(pod, container, nil, "", "")
if err != nil {
return "", err
}

// Set OOM score of POD container to lower than those of the other
// containers in the pod. This ensures that it is killed only as a last
// resort.
containerInfo, err := kl.dockerClient.InspectContainer(string(id))
if err != nil {
return "", err
}

return id, util.ApplyOomScoreAdj(containerInfo.State.Pid, podOomScoreAdj)
}

func (kl *Kubelet) pullImage(img string, ref *api.ObjectReference) error {
Expand Down
14 changes: 7 additions & 7 deletions pkg/kubelet/kubelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ func TestSyncPodsWithTerminationLog(t *testing.T) {
}
kubelet.drainWorkers()
verifyCalls(t, fakeDocker, []string{
"list", "create", "start", "list", "inspect_container", "inspect_image", "list", "create", "start"})
"list", "create", "start", "inspect_container", "list", "inspect_container", "inspect_image", "list", "create", "start"})

fakeDocker.Lock()
parts := strings.Split(fakeDocker.Container.HostConfig.Binds[0], ":")
Expand Down Expand Up @@ -497,7 +497,7 @@ func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
kubelet.drainWorkers()

verifyCalls(t, fakeDocker, []string{
"list", "create", "start", "list", "inspect_container", "inspect_image", "list", "create", "start"})
"list", "create", "start", "inspect_container", "list", "inspect_container", "inspect_image", "list", "create", "start"})

fakeDocker.Lock()

Expand Down Expand Up @@ -547,7 +547,7 @@ func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
kubelet.drainWorkers()

verifyCalls(t, fakeDocker, []string{
"list", "create", "start", "list", "inspect_container", "inspect_image", "list", "create", "start"})
"list", "create", "start", "inspect_container", "list", "inspect_container", "inspect_image", "list", "create", "start"})

fakeDocker.Lock()

Expand All @@ -563,7 +563,7 @@ func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
fakeDocker.Unlock()
}

func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
func TestSyncPodsWithPodInfraCreatesContainer(t *testing.T) {
kubelet, fakeDocker := newTestKubelet(t)
fakeDocker.ContainerList = []docker.APIContainers{
{
Expand Down Expand Up @@ -604,7 +604,7 @@ func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
fakeDocker.Unlock()
}

func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
func TestSyncPodsWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
kubelet, fakeDocker := newTestKubelet(t)
fakeHttp := fakeHTTP{}
kubelet.httpClient = &fakeHttp
Expand Down Expand Up @@ -661,7 +661,7 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
}
}

func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
func TestSyncPodsDeletesWithNoPodInfraContainer(t *testing.T) {
kubelet, fakeDocker := newTestKubelet(t)
fakeDocker.ContainerList = []docker.APIContainers{
{
Expand Down Expand Up @@ -692,7 +692,7 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
kubelet.drainWorkers()

verifyCalls(t, fakeDocker, []string{
"list", "stop", "create", "start", "list", "list", "inspect_container", "inspect_image", "list", "create", "start"})
"list", "stop", "create", "start", "inspect_container", "list", "list", "inspect_container", "inspect_image", "list", "create", "start"})

// A map iteration is used to delete containers, so must not depend on
// order here.
Expand Down
18 changes: 16 additions & 2 deletions pkg/kubelet/runonce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,28 @@ func TestRunOnce(t *testing.T) {
label: "syncPod",
container: docker.Container{
Config: &docker.Config{Image: "someimage"},
State: docker.State{Running: true},
State: docker.State{Running: true, Pid: 42},
},
},
{
label: "syncPod",
container: docker.Container{
Config: &docker.Config{Image: "someimage"},
State: docker.State{Running: true},
State: docker.State{Running: true, Pid: 42},
},
},
{
label: "syncPod",
container: docker.Container{
Config: &docker.Config{Image: "someimage"},
State: docker.State{Running: true, Pid: 42},
},
},
{
label: "syncPod",
container: docker.Container{
Config: &docker.Config{Image: "someimage"},
State: docker.State{Running: true, Pid: 42},
},
},
},
Expand Down

0 comments on commit 8649628

Please sign in to comment.