![image]()
cmd\kube-controller-manager\app\apps.go
startDaemonSetController
func startNamespaceController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
...
return startModifiedNamespaceController(ctx, controllerContext, namespaceKubeClient, nsKubeconfig)
}
startModifiedNamespaceController
func startModifiedNamespaceController(ctx context.Context, controllerContext ControllerContext, namespaceKubeClient clientset.Interface, nsKubeconfig *restclient.Config) (controller.Interface, bool, error) {
metadataClient, err := metadata.NewForConfig(nsKubeconfig)
discoverResourcesFn := namespaceKubeClient.Discovery().ServerPreferredNamespacedResources
namespaceController := namespacecontroller.NewNamespaceController(
namespaceKubeClient,
metadataClient,
discoverResourcesFn,
controllerContext.InformerFactory.Core().V1().Namespaces(), // 仅关注ns对象
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
func 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,
)
}
enqueueNamespace
func (nm *NamespaceController) enqueueNamespace(obj interface{}) {
key, err := controller.KeyFunc(obj)
namespace := obj.(*v1.Namespace)
// ns已经被标识删除就不用重复处理了
if namespace.DeletionTimestamp == nil || namespace.DeletionTimestamp.IsZero() {
return
}
nm.queue.AddAfter(key, namespaceDeletionGracePeriod)
}
Run
func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) {
...
for i := 0; i < workers; i++ {
go wait.Until(nm.worker, time.Second, stopCh)
}
<-stopCh
}
worker
func (nm *NamespaceController) worker() {
workFunc := func() bool {
key, quit := nm.queue.Get()
err := nm.syncNamespaceFromKey(key.(string))
...
return false
}
...
}
syncNamespaceFromKey
func (nm *NamespaceController) syncNamespaceFromKey(key string) (err error) {
namespace, err := nm.lister.Get(key)
return nm.namespacedResourcesDeleter.Delete(namespace.Name)
}
pkg\controller\namespace\deletion\namespaced_resources_deleter.go
Delete
func (d *namespacedResourcesDeleter) Delete(nsName string) error {
namespace, err := d.nsClient.Get(context.TODO(), nsName, metav1.GetOptions{})
if namespace.DeletionTimestamp == nil {
return nil
}
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)
return nil
}
updateNamespaceStatusFunc
func (d *namespacedResourcesDeleter) updateNamespaceStatusFunc(namespace *v1.Namespace) (*v1.Namespace, error) {
if namespace.DeletionTimestamp.IsZero() || namespace.Status.Phase == v1.NamespaceTerminating {
return namespace, nil
}
newNamespace := namespace.DeepCopy()
newNamespace.Status.Phase = v1.NamespaceTerminating // 更新ns为Terminating状态
return d.nsClient.UpdateStatus(context.TODO(), newNamespace, metav1.UpdateOptions{})
}
finalizeNamespace
func (d *namespacedResourcesDeleter) finalizeNamespace(namespace *v1.Namespace) (*v1.Namespace, error) {
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{}) // 冻结掉ns下所有资源
if err != nil {
if errors.IsNotFound(err) {
return namespace, nil
}
}
return namespace, err
}
deleteAllContent
func (d *namespacedResourcesDeleter) deleteAllContent(ns *v1.Namespace) (int64, error) {
...
deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"delete"}}, resources)
// 使用dynamic client因为ns下可能有crd资源
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
}
}
}
...
}