美文网首页
Using Finalizers

Using Finalizers

作者: allenhaozi | 来源:发表于2020-09-16 17:27 被阅读0次

    Finalizers allow controllers to implement asynchronous pre-delete hooks. Let’s say you create an external resource (such as a storage bucket) for each object of your API type, and you want to delete the associated external resource on object’s deletion from Kubernetes, you can use a finalizer to do that.

    You can read more about the finalizers in the Kubernetes reference docs. The section below demonstrates how to register and trigger pre-delete hooks in the Reconcile method of a controller.

    The key point to note is that a finalizer causes “delete” on the object to become an “update” to set deletion timestamp. Presence of deletion timestamp on the object indicates that it is being deleted. Otherwise, without finalizers, a delete shows up as a reconcile where the object is missing from the cache.

    Highlights:

    • If the object is not being deleted and does not have the finalizer registered, then add the finalizer and update the object in Kubernetes.
    • If object is being deleted and the finalizer is still present in finalizers list, then execute the pre-delete logic and remove the finalizer and update the object.
    • Ensure that the pre-delete logic is idempotent.
    func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
        ctx := context.Background()
        log := r.Log.WithValues("cronjob", req.NamespacedName)
    
        var cronJob *batchv1.CronJob
        if err := r.Get(ctx, req.NamespacedName, cronJob); err != nil {
            log.Error(err, "unable to fetch CronJob")
            // we'll ignore not-found errors, since they can't be fixed by an immediate
            // requeue (we'll need to wait for a new notification), and we can get them
            // on deleted requests.
            return ctrl.Result{}, client.IgnoreNotFound(err)
        }
    
        // name of our custom finalizer
        myFinalizerName := "storage.finalizers.tutorial.kubebuilder.io"
    
        // examine DeletionTimestamp to determine if object is under deletion
        if cronJob.ObjectMeta.DeletionTimestamp.IsZero() {
            // The object is not being deleted, so if it does not have our finalizer,
            // then lets add the finalizer and update the object. This is equivalent
            // registering our finalizer.
            if !containsString(cronJob.ObjectMeta.Finalizers, myFinalizerName) {
                cronJob.ObjectMeta.Finalizers = append(cronJob.ObjectMeta.Finalizers, myFinalizerName)
                if err := r.Update(context.Background(), cronJob); err != nil {
                    return ctrl.Result{}, err
                }
            }
        } else {
            // The object is being deleted
            if containsString(cronJob.ObjectMeta.Finalizers, myFinalizerName) {
                // our finalizer is present, so lets handle any external dependency
                if err := r.deleteExternalResources(cronJob); err != nil {
                    // if fail to delete the external dependency here, return with error
                    // so that it can be retried
                    return ctrl.Result{}, err
                }
    
                // remove our finalizer from the list and update it.
                cronJob.ObjectMeta.Finalizers = removeString(cronJob.ObjectMeta.Finalizers, myFinalizerName)
                if err := r.Update(context.Background(), cronJob); err != nil {
                    return ctrl.Result{}, err
                }
            }
    
            // Stop reconciliation as the item is being deleted
            return ctrl.Result{}, nil
        }
    
        // Your reconcile logic
    
        return ctrl.Result{}, nil
    }
    
    func (r *Reconciler) deleteExternalResources(cronJob *batch.CronJob) error {
        //
        // delete any external resources associated with the cronJob
        //
        // Ensure that delete implementation is idempotent and safe to invoke
        // multiple types for same object.
    }
    
    // Helper functions to check and remove string from a slice of strings.
    func containsString(slice []string, s string) bool {
        for _, item := range slice {
            if item == s {
                return true
            }
        }
        return false
    }
    
    func removeString(slice []string, s string) (result []string) {
        for _, item := range slice {
            if item == s {
                continue
            }
            result = append(result, item)
        }
        return
    }
    

    https://book.kubebuilder.io/reference/using-finalizers.html

    相关文章

      网友评论

          本文标题:Using Finalizers

          本文链接:https://www.haomeiwen.com/subject/hndhyktx.html