diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index 36d0e429524..97d9419a669 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -62,6 +62,8 @@ const ( minimumDockerAPIVersion = "1.20" + dockerv110APIVersion = "1.21" + // ndots specifies the minimum number of dots that a domain name must contain for the resolver to consider it as FQDN (fully-qualified) // we want to able to consider SRV lookup names like _dns._udp.kube-dns.default.svc to be considered relative. // hence, setting ndots to be 5. @@ -503,7 +505,8 @@ func (dm *DockerManager) runContainer( ipcMode string, utsMode string, pidMode string, - restartCount int) (kubecontainer.ContainerID, error) { + restartCount int, + oomScoreAdj int) (kubecontainer.ContainerID, error) { dockerName := KubeletContainerName{ PodFullName: kubecontainer.GetPodFullName(pod), @@ -584,6 +587,11 @@ func (dm *DockerManager) runContainer( SecurityOpt: securityOpts, } + // If current api version is newer than docker 1.10 requested, set OomScoreAdj to HostConfig + if dm.checkDockerAPIVersion(dockerv110APIVersion) >= 0 { + hc.OomScoreAdj = oomScoreAdj + } + if dm.cpuCFSQuota { // if cpuLimit.Amount is nil, then the appropriate default value is returned to allow full usage of cpu resource. cpuQuota, cpuPeriod := milliCPUToQuota(cpuLimit.MilliValue()) @@ -1473,7 +1481,20 @@ func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Containe if usesHostNetwork(pod) { utsMode = namespaceModeHost } - id, err := dm.runContainer(pod, container, opts, ref, netMode, ipcMode, utsMode, pidMode, restartCount) + + // Set OOM score of the container based on the priority of the container. + // Processes in lower-priority pods should be killed first if the system runs out of memory. + // The main pod infrastructure container is considered high priority, since if it is killed the + // whole pod will die. + var oomScoreAdj int + if container.Name == PodInfraContainerName { + oomScoreAdj = qos.PodInfraOOMAdj + } else { + oomScoreAdj = qos.GetContainerOOMScoreAdjust(container, int64(dm.machineInfo.MemoryCapacity)) + + } + + id, err := dm.runContainer(pod, container, opts, ref, netMode, ipcMode, utsMode, pidMode, restartCount, oomScoreAdj) if err != nil { return kubecontainer.ContainerID{}, fmt.Errorf("runContainer: %v", err) } @@ -1512,9 +1533,12 @@ func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Containe return kubecontainer.ContainerID{}, fmt.Errorf("can't get init PID for container %q", id) } - if err := dm.applyOOMScoreAdj(container, containerInfo); err != nil { - return kubecontainer.ContainerID{}, fmt.Errorf("failed to apply oom-score-adj to container %q- %v", err, containerInfo.Name) + // Check if current docker version is higher than 1.10. Otherwise, we have to apply OOMScoreAdj instead of using docker API. + err = dm.applyOOMScoreAdjIfNeeded(container, containerInfo) + if err != nil { + return kubecontainer.ContainerID{}, err } + // The addNDotsOption call appends the ndots option to the resolv.conf file generated by docker. // This resolv.conf file is shared by all containers of the same pod, and needs to be modified only once per pod. // we modify it when the pause container is created since it is the first container created in the pod since it holds @@ -1529,6 +1553,38 @@ func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Containe return id, err } +func (dm *DockerManager) applyOOMScoreAdjIfNeeded(container *api.Container, containerInfo *docker.Container) error { + // Compare current API version with expected api version + result := dm.checkDockerAPIVersion(dockerv110APIVersion) + // If current api version is older than OOMScoreAdj requested, use the old way. + if result < 0 { + if err := dm.applyOOMScoreAdj(container, containerInfo); err != nil { + return fmt.Errorf("failed to apply oom-score-adj to container %q- %v", err, containerInfo.Name) + } + } + + return nil +} + +// Check current docker API version against expected version. +// Return: +// 1 : newer than expected version +// -1: older than expected version +// 0 : same version +func (dm *DockerManager) checkDockerAPIVersion(expectedVersion string) int { + apiVersion, err := dm.APIVersion() + if err != nil { + glog.Errorf("failed to get current docker version - %v", err) + } + + result, err := apiVersion.Compare(expectedVersion) + if err != nil { + glog.Errorf("failed to compare current docker version %v with OOMScoreAdj supported Docker version %q - %v", + apiVersion, expectedVersion, err) + } + return result +} + func addNDotsOption(resolvFilePath string) error { if len(resolvFilePath) == 0 { glog.Errorf("ResolvConfPath is empty.")