Change:
Kubelet evicts pods whenever there is memory or disk pressure. It marks the pods as to evict them. To help with reducing disk pressure, kubelet should delete all containers belonging to pods right away. This will result in loss of logs. In the future, we can copy out logs from dead containers before deleting them. Logs can be rotated separately from dead containers. IMO, this feature is required for disk usage based evictions to work reliably in kubelet.

Discussion:
} return resourceToRankFunc } <ins> func PodIsEvicted(podStatus api.PodStatus) bool { return podStatus.Phase == api.PodFailed && podStatus.Reason == reason } </ins>

glog.V(2).Infof("SyncLoop (PLEG): %q, event: %#v", format.Pod(pod), e) handler.HandlePodSyncs([]*api.Pod{pod}) } if e.Type == pleg.ContainerDied { <del> if podStatus, err := kl.podCache.Get(e.ID); err == nil { if containerID, ok := e.Data.(string); ok { kl.containerDeletor.deleteContainersInPod(containerID, podStatus) } </del> <ins> if containerID, ok := e.Data.(string); ok { kl.cleanUpContainersInPod(e.ID, containerID) </ins> } } case <-syncCh:

server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer, address, port, kl.containerRuntime) } <ins> // Delete the eligible dead container instances in a pod. Depending on the configuration, the latest dead containers may be kept around. func (kl *Kubelet) cleanUpContainersInPod(podId types.UID, exitedContainerID string) { if podStatus, err := kl.podCache.Get(podId); err == nil { if status, ok := kl.statusManager.GetPodStatus(podId); ok { // If a pod is evicted, we can delete all the dead containers. kl.containerDeletor.deleteContainersInPod(exitedContainerID, podStatus, eviction.PodIsEvicted(status)) } } } </ins> // isSyncPodWorthy filters out events that are not worthy of pod syncing func isSyncPodWorthy(event *pleg.PodLifecycleEvent) bool { // ContatnerRemoved doesn't affect pod state

} // getContainersToDeleteInPod returns the exited containers in a pod whose name matches the name inferred from exitedContainerID, ordered by the creation time from the latest to the earliest. <del> func (p *podContainerDeletor) getContainersToDeleteInPod(exitedContainerID string, podStatus *kubecontainer.PodStatus) containerStatusbyCreatedList { </del> <ins> func getContainersToDeleteInPod(exitedContainerID string, podStatus *kubecontainer.PodStatus, containersToKeep int) containerStatusbyCreatedList { </ins> var matchedContainer *kubecontainer.ContainerStatus var exitedContainers []*kubecontainer.ContainerStatus // Find all exited containers in the pod

candidates = append(candidates, containerStatus) } } <del> if len(candidates) <= p.containersToKeep { </del> <ins> if len(candidates) <= containersToKeep { </ins> return containerStatusbyCreatedList{} } sort.Sort(candidates) <del> return candidates[p.containersToKeep:] </del> <ins> return candidates[containersToKeep:] </ins> } // deleteContainersInPod issues container deletion requests for containers selected by getContainersToDeleteInPod. <del> func (p *podContainerDeletor) deleteContainersInPod(exitedContainerID string, podStatus *kubecontainer.PodStatus) { for _, candidate := range p.getContainersToDeleteInPod(exitedContainerID, podStatus) { </del> <ins> func (p *podContainerDeletor) deleteContainersInPod(exitedContainerID string, podStatus *kubecontainer.PodStatus, removeAll bool) { containersToKeep := p.containersToKeep if removeAll { containersToKeep = 0 } for _, candidate := range getContainersToDeleteInPod(exitedContainerID, podStatus, containersToKeep) { </ins> select { case p.worker <- candidate.ID: default:

"time" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" <del> containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" </del> ) func testGetContainersToDeleteInPod(t *testing.T) {

}, } <del> expectedCandidates := []*kubecontainer.ContainerStatus{pod.ContainerStatuses[2], pod.ContainerStatuses[1]} candidates := newPodContainerDeletor(&containertest.FakeRuntime{}, 1).getContainersToDeleteInPod("2", &pod) if !reflect.DeepEqual(candidates, expectedCandidates) { t.Errorf("expected %v got %v", expectedCandidates, candidates) </del> <ins> testCases := []struct { containersToKeep           int expectedContainersToDelete []*kubecontainer.ContainerStatus }{ { 0, []*kubecontainer.ContainerStatus{pod.ContainerStatuses[3], pod.ContainerStatuses[2], pod.ContainerStatuses[1]}, }, { 1, []*kubecontainer.ContainerStatus{pod.ContainerStatuses[2], pod.ContainerStatuses[1]}, }, { 2, []*kubecontainer.ContainerStatus{pod.ContainerStatuses[1]}, }, } for _, test := range testCases { candidates := getContainersToDeleteInPod("4", &pod, test.containersToKeep) if !reflect.DeepEqual(getContainersToDeleteInPod("4", &pod, test.containersToKeep), test.expectedContainersToDelete) { t.Errorf("expected %v got %v", test.expectedContainersToDelete, candidates) } </ins> } }