| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2016-06-03 08:25:58 +08:00
										 |  |  | Copyright 2015 The Kubernetes Authors. | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | See the License for the specific language governing permissions and | 
					
						
							|  |  |  | limitations under the License. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 06:43:57 +08:00
										 |  |  | package podgc | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/api/v1" | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/client/cache" | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5" | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/controller" | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/controller/informers" | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/labels" | 
					
						
							|  |  |  | 	"k8s.io/kubernetes/pkg/runtime" | 
					
						
							| 
									
										
										
										
											2016-04-14 02:38:32 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/util/metrics" | 
					
						
							| 
									
										
										
										
											2016-01-15 15:32:10 +08:00
										 |  |  | 	utilruntime "k8s.io/kubernetes/pkg/util/runtime" | 
					
						
							| 
									
										
										
										
											2016-02-02 18:57:06 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/util/wait" | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	"k8s.io/kubernetes/pkg/watch" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/golang/glog" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-10-06 17:12:00 +08:00
										 |  |  | 	gcCheckPeriod = 20 * time.Second | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 06:43:57 +08:00
										 |  |  | type PodGCController struct { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	kubeClient clientset.Interface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// internalPodInformer is used to hold a personal informer.  If we're using
 | 
					
						
							|  |  |  | 	// a normal shared informer, then the informer will be started for us.  If
 | 
					
						
							|  |  |  | 	// we have a personal informer, we must start it ourselves.   If you start
 | 
					
						
							|  |  |  | 	// the controller using NewPodGC(..., passing SharedInformer, ...), this
 | 
					
						
							|  |  |  | 	// will be null
 | 
					
						
							|  |  |  | 	internalPodInformer cache.SharedIndexInformer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	podStore  cache.StoreToPodLister | 
					
						
							|  |  |  | 	nodeStore cache.StoreToNodeLister | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	podController  cache.ControllerInterface | 
					
						
							|  |  |  | 	nodeController cache.ControllerInterface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	deletePod              func(namespace, name string) error | 
					
						
							|  |  |  | 	terminatedPodThreshold int | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | func NewPodGC(kubeClient clientset.Interface, podInformer cache.SharedIndexInformer, terminatedPodThreshold int) *PodGCController { | 
					
						
							| 
									
										
										
										
											2016-10-13 20:56:07 +08:00
										 |  |  | 	if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { | 
					
						
							|  |  |  | 		metrics.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.Core().RESTClient().GetRateLimiter()) | 
					
						
							| 
									
										
										
										
											2016-04-14 02:38:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-07 06:43:57 +08:00
										 |  |  | 	gcc := &PodGCController{ | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 		kubeClient:             kubeClient, | 
					
						
							|  |  |  | 		terminatedPodThreshold: terminatedPodThreshold, | 
					
						
							| 
									
										
										
										
											2015-10-10 08:15:00 +08:00
										 |  |  | 		deletePod: func(namespace, name string) error { | 
					
						
							| 
									
										
										
										
											2016-11-16 22:00:01 +08:00
										 |  |  | 			glog.Infof("PodGC is force deleting Pod: %v:%v", namespace, name) | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 			return kubeClient.Core().Pods(namespace).Delete(name, v1.NewDeleteOptions(0)) | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	gcc.podStore.Indexer = podInformer.GetIndexer() | 
					
						
							|  |  |  | 	gcc.podController = podInformer.GetController() | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	gcc.nodeStore.Store, gcc.nodeController = cache.NewInformer( | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 		&cache.ListWatch{ | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 			ListFunc: func(options v1.ListOptions) (runtime.Object, error) { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 				return gcc.kubeClient.Core().Nodes().List(options) | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 			WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 				return gcc.kubeClient.Core().Nodes().Watch(options) | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | 		&v1.Node{}, | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 		controller.NoResyncPeriodFunc(), | 
					
						
							| 
									
										
										
										
											2016-09-15 02:35:38 +08:00
										 |  |  | 		cache.ResourceEventHandlerFuncs{}, | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	return gcc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | func NewFromClient( | 
					
						
							|  |  |  | 	kubeClient clientset.Interface, | 
					
						
							|  |  |  | 	terminatedPodThreshold int, | 
					
						
							|  |  |  | ) *PodGCController { | 
					
						
							|  |  |  | 	podInformer := informers.NewPodInformer(kubeClient, controller.NoResyncPeriodFunc()) | 
					
						
							|  |  |  | 	controller := NewPodGC(kubeClient, podInformer, terminatedPodThreshold) | 
					
						
							|  |  |  | 	controller.internalPodInformer = podInformer | 
					
						
							|  |  |  | 	return controller | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 06:43:57 +08:00
										 |  |  | func (gcc *PodGCController) Run(stop <-chan struct{}) { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	if gcc.internalPodInformer != nil { | 
					
						
							|  |  |  | 		go gcc.podController.Run(stop) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go gcc.nodeController.Run(stop) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:57:06 +08:00
										 |  |  | 	go wait.Until(gcc.gc, gcCheckPeriod, stop) | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	<-stop | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 06:43:57 +08:00
										 |  |  | func (gcc *PodGCController) gc() { | 
					
						
							| 
									
										
										
										
											2016-10-14 20:40:08 +08:00
										 |  |  | 	if !gcc.podController.HasSynced() || !gcc.nodeController.HasSynced() { | 
					
						
							|  |  |  | 		glog.V(2).Infof("PodGCController is waiting for informer sync...") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	pods, err := gcc.podStore.List(labels.Everything()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		glog.Errorf("Error while listing all Pods: %v", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if gcc.terminatedPodThreshold > 0 { | 
					
						
							|  |  |  | 		gcc.gcTerminated(pods) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gcc.gcOrphaned(pods) | 
					
						
							| 
									
										
										
										
											2016-10-26 02:18:58 +08:00
										 |  |  | 	gcc.gcUnscheduledTerminating(pods) | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | func isPodTerminated(pod *v1.Pod) bool { | 
					
						
							|  |  |  | 	if phase := pod.Status.Phase; phase != v1.PodPending && phase != v1.PodRunning && phase != v1.PodUnknown { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | func (gcc *PodGCController) gcTerminated(pods []*v1.Pod) { | 
					
						
							|  |  |  | 	terminatedPods := []*v1.Pod{} | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	for _, pod := range pods { | 
					
						
							|  |  |  | 		if isPodTerminated(pod) { | 
					
						
							|  |  |  | 			terminatedPods = append(terminatedPods, pod) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 	terminatedPodCount := len(terminatedPods) | 
					
						
							|  |  |  | 	sort.Sort(byCreationTimestamp(terminatedPods)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	deleteCount := terminatedPodCount - gcc.terminatedPodThreshold | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if deleteCount > terminatedPodCount { | 
					
						
							|  |  |  | 		deleteCount = terminatedPodCount | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if deleteCount > 0 { | 
					
						
							|  |  |  | 		glog.Infof("garbage collecting %v pods", deleteCount) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var wait sync.WaitGroup | 
					
						
							|  |  |  | 	for i := 0; i < deleteCount; i++ { | 
					
						
							|  |  |  | 		wait.Add(1) | 
					
						
							|  |  |  | 		go func(namespace string, name string) { | 
					
						
							|  |  |  | 			defer wait.Done() | 
					
						
							| 
									
										
										
										
											2015-10-10 08:15:00 +08:00
										 |  |  | 			if err := gcc.deletePod(namespace, name); err != nil { | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 				// ignore not founds
 | 
					
						
							| 
									
										
										
										
											2016-01-15 15:32:10 +08:00
										 |  |  | 				defer utilruntime.HandleError(err) | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}(terminatedPods[i].Namespace, terminatedPods[i].Name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	wait.Wait() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 02:18:58 +08:00
										 |  |  | // gcOrphaned deletes pods that are bound to nodes that don't exist.
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | func (gcc *PodGCController) gcOrphaned(pods []*v1.Pod) { | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 	glog.V(4).Infof("GC'ing orphaned") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, pod := range pods { | 
					
						
							|  |  |  | 		if pod.Spec.NodeName == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, exists, _ := gcc.nodeStore.GetByKey(pod.Spec.NodeName); exists { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		glog.V(2).Infof("Found orphaned Pod %v assigned to the Node %v. Deleting.", pod.Name, pod.Spec.NodeName) | 
					
						
							|  |  |  | 		if err := gcc.deletePod(pod.Namespace, pod.Name); err != nil { | 
					
						
							|  |  |  | 			utilruntime.HandleError(err) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-10-28 04:30:04 +08:00
										 |  |  | 			glog.V(0).Infof("Forced deletion of orphaned Pod %s succeeded", pod.Name) | 
					
						
							| 
									
										
										
										
											2016-10-26 02:18:58 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // gcUnscheduledTerminating deletes pods that are terminating and haven't been scheduled to a particular node.
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | func (gcc *PodGCController) gcUnscheduledTerminating(pods []*v1.Pod) { | 
					
						
							| 
									
										
										
										
											2016-10-26 02:18:58 +08:00
										 |  |  | 	glog.V(4).Infof("GC'ing unscheduled pods which are terminating.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, pod := range pods { | 
					
						
							| 
									
										
										
										
											2016-10-28 04:30:04 +08:00
										 |  |  | 		if pod.DeletionTimestamp == nil || len(pod.Spec.NodeName) > 0 { | 
					
						
							| 
									
										
										
										
											2016-10-26 02:18:58 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		glog.V(2).Infof("Found unscheduled terminating Pod %v not assigned to any Node. Deleting.", pod.Name) | 
					
						
							|  |  |  | 		if err := gcc.deletePod(pod.Namespace, pod.Name); err != nil { | 
					
						
							|  |  |  | 			utilruntime.HandleError(err) | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-10-28 04:30:04 +08:00
										 |  |  | 			glog.V(0).Infof("Forced deletion of unscheduled terminating Pod %s succeeded", pod.Name) | 
					
						
							| 
									
										
										
										
											2016-09-12 22:47:17 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | // byCreationTimestamp sorts a list by creation timestamp, using their names as a tie breaker.
 | 
					
						
							| 
									
										
										
										
											2016-11-19 04:50:17 +08:00
										 |  |  | type byCreationTimestamp []*v1.Pod | 
					
						
							| 
									
										
										
										
											2015-09-22 06:51:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (o byCreationTimestamp) Len() int      { return len(o) } | 
					
						
							|  |  |  | func (o byCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (o byCreationTimestamp) Less(i, j int) bool { | 
					
						
							|  |  |  | 	if o[i].CreationTimestamp.Equal(o[j].CreationTimestamp) { | 
					
						
							|  |  |  | 		return o[i].Name < o[j].Name | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return o[i].CreationTimestamp.Before(o[j].CreationTimestamp) | 
					
						
							|  |  |  | } |