cmd\kube-controller-manager\app\core.go
func startNamespaceController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
return startModifiedNamespaceController(ctx, controllerContext, namespaceKubeClient, nsKubeconfig)
}
func startModifiedNamespaceController(ctx context.Context, controllerContext ControllerContext, namespaceKubeClient clientset.Interface, nsKubeconfig *restclient.Config) (controller.Interface, bool, error) {
namespaceController := namespacecontroller.NewNamespaceController(
namespaceKubeClient,
metadataClient,
discoverResourcesFn,
controllerContext.InformerFactory.Core().V1().Namespaces(),
controllerContext.ComponentConfig.NamespaceController.NamespaceSyncPeriod.Duration,
v1.FinalizerKubernetes,
)
go namespaceController.Run(int(controllerContext.ComponentConfig.NamespaceController.ConcurrentNamespaceSyncs), ctx.Done())
return nil, true, nil
}
pkg\controller\namespace\namespace_controller.go
NewNamespaceController
namespaceInformer.Informer().AddEventHandlerWithResyncPeriod(
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
namespace := obj.(*v1.Namespace)
namespaceController.enqueueNamespace(namespace)
},
UpdateFunc: func(oldObj, newObj interface{}) {
namespace := newObj.(*v1.Namespace)
namespaceController.enqueueNamespace(namespace)
},
},
resyncPeriod,
)
Run
go wait.Until(nm.worker, time.Second, stopCh)
worker
workFunc := func() bool {
key, quit := nm.queue.Get()
if quit {
return true
}
defer nm.queue.Done(key)
err := nm.syncNamespaceFromKey(key.(string))
if err == nil {
// no error, forget this entry and return
nm.queue.Forget(key)
return false
}
if estimate, ok := err.(*deletion.ResourcesRemainingError); ok {
// 等待预估时间再次入队
t := estimate.Estimate/2 + 1
nm.queue.AddAfter(key, time.Duration(t)*time.Second)
} else {
// 有其他错误不等待直接入队下次处理
nm.queue.AddRateLimited(key)
}
return false
}
for {
quit := workFunc()
if quit {
return
}
}
syncNamespaceFromKey
...
return nm.namespacedResourcesDeleter.Delete(namespace.Name) --->pkg\controller\namespace\deletion\namespaced_resources_deleter.go
pkg\controller\namespace\deletion\namespaced_resources_deleter.go
**Delete**
// 获取namespace
namespace, err := d.nsClient.Get(context.TODO(), nsName, metav1.GetOptions{})
...
// 使用updateNamespaceStatusFunc方法将namespace强制更新,保证其是最新的状态
namespace, err = d.retryOnConflictError(namespace, d.updateNamespaceStatusFunc)
...
if namespace.DeletionTimestamp.IsZero() {
return nil
}
// 可以进行非级联删除,直接返回
if finalized(namespace) {
return nil
}
// 删除namespace下所有资源
estimate, err := d.deleteAllContent(namespace)
...
// 使用finalizeNamespace冻结namespace
_, err = d.retryOnConflictError(namespace, d.finalizeNamespace)
func (d *namespacedResourcesDeleter) retryOnConflictError(namespace *v1.Namespace, fn updateNamespaceFunc) (result *v1.Namespace, err error) {
for {
...
result, err = fn(latestNamespace)
...
}
}
// 更新当前newNamespace
updateNamespaceStatusFunc
...
newNamespace := namespace.DeepCopy()
newNamespace.Status.Phase = v1.NamespaceTerminating
return d.nsClient.UpdateStatus(context.TODO(), newNamespace, metav1.UpdateOptions{})
// 冻结当前newNamespace
finalizeNamespace
namespaceFinalize := v1.Namespace{}
namespaceFinalize.ObjectMeta = namespace.ObjectMeta
namespaceFinalize.Spec = namespace.Spec
finalizerSet := sets.NewString()
for i := range namespace.Spec.Finalizers {
if namespace.Spec.Finalizers[i] != d.finalizerToken {
finalizerSet.Insert(string(namespace.Spec.Finalizers[i]))
}
}
namespaceFinalize.Spec.Finalizers = make([]v1.FinalizerName, 0, len(finalizerSet))
for _, value := range finalizerSet.List() {
namespaceFinalize.Spec.Finalizers = append(namespaceFinalize.Spec.Finalizers, v1.FinalizerName(value))
}
namespace, err := d.nsClient.Finalize(context.Background(), &namespaceFinalize, metav1.UpdateOptions{})
return namespace, err
// 删除该namespace下所有资源,并预估删除时间
**deleteAllContent**
...
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, resources)
groupVersionResources, err := discovery.GroupVersionResources(deletableResources)
...
// 删除各资源并预估其删除时间
for gvr := range groupVersionResources {
gvrDeletionMetadata, err := d.deleteAllContentForGroupVersionResource(gvr, namespace, namespaceDeletedAt)
if gvrDeletionMetadata.finalizerEstimateSeconds > estimate {
estimate = gvrDeletionMetadata.finalizerEstimateSeconds
}
if gvrDeletionMetadata.numRemaining > 0 {
numRemainingTotals.gvrToNumRemaining[gvr] = gvrDeletionMetadata.numRemaining
for finalizer, numRemaining := range gvrDeletionMetadata.finalizersToNumRemaining {
if numRemaining == 0 {
continue
}
numRemainingTotals.finalizersToNumRemaining[finalizer] = numRemainingTotals.finalizersToNumRemaining[finalizer] + numRemaining
}
}
}