Using Finalizers
Finalizers
allow controllers to implement asynchronous pre-delete hooks. Letsay you create an external resource such as a storage bucket for each object ofthe API type you are implementing and you would like to clean up the external resourcewhen the corresponding object is deleted from Kubernetes, you can use afinalizer to delete the external resource.
You can read more about the finalizers in the kubernetes reference docs. Section belowdemonstrates how to register and trigger pre-delete hooks in the Reconcile
method of a controller.
Highlights:
- If 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 theobject.
- You should implement the pre-delete logic in such a way that it is safe to invoke it multiple times for the same object.
func (r *Reconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
err := r.Get(context.TODO(), request.NamespacedName, instance)
if err != nil {
// handle error
}
// name of your custom finalizer
myFinalizerName := "storage.finalizers.example.com"
if instance.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.
if !containsString(instance.ObjectMeta.Finalizers, myFinalizerName) {
instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, myFinalizerName)
if err := r.Update(context.Background(), instance); err != nil {
return reconcile.Result{}, err
}
}
} else {
// The object is being deleted
if containsString(instance.ObjectMeta.Finalizers, myFinalizerName) {
// our finalizer is present, so lets handle our external dependency
if err := r.deleteExternalDependency(instance); err != nil {
// if fail to delete the external dependency here, return with error
// so that it can be retried
return reconcile.Result{}, err
}
// remove our finalizer from the list and update it.
instance.ObjectMeta.Finalizers = removeString(instance.ObjectMeta.Finalizers, myFinalizerName)
if err := r.Update(context.Background(), instance); err != nil {
return reconcile.Result{}, err
}
}
// Our finalizer has finished, so the reconciler can do nothing.
return reconcile.Result{}, nil
}
....
....
}
func (r *Reconciler) deleteExternalDependency(instance *MyType) error {
log.Printf("deleting the external dependencies")
//
// delete the external dependency here
//
// 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
}
当前内容版权归 kubebuilder.io 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 kubebuilder.io .