Finalizers -- Controlling Resource Cleanup
Finalizers are a mechanism that prevents a resource from being deleted until specific cleanup tasks are completed. They are the most common reason a resource gets stuck in the "Terminating" state.
What Are Finalizers?
A finalizer is a string stored in a resource's metadata.finalizers list. When you delete a resource that has finalizers, Kubernetes marks it for deletion but does not actually remove it. The resource stays in a Terminating state until all finalizers are removed.
# Check if a resource has finalizers
kubectl get namespace stuck-namespace -o jsonpath='{.metadata.finalizers}'
How Finalizers Work
The lifecycle of a resource with finalizers:
- You run
kubectl delete - Kubernetes sets
metadata.deletionTimestampon the resource - A controller that registered the finalizer performs cleanup work
- The controller removes its finalizer from the list
- Once the finalizer list is empty, Kubernetes deletes the resource
Common Kubernetes finalizers include:
kubernetes.io/pv-protection-- prevents deleting PersistentVolumes that are in useforegroundDeletion-- used by the garbage collector for foreground cascading deletes
Stuck Resources
The most common problem with finalizers is resources that get stuck in Terminating. This happens when:
- The controller responsible for the finalizer is not running
- The controller cannot complete its cleanup task
- A custom finalizer was added but no controller handles it
Diagnosing Stuck Resources
When a resource is stuck, check its finalizers:
# For a stuck namespace
kubectl get namespace stuck-namespace -o yaml
# Look for the finalizers field and deletionTimestamp
# metadata:
# deletionTimestamp: "2025-01-15T10:00:00Z"
# finalizers:
# - kubernetes
Removing Finalizers
If you are sure the cleanup is no longer needed, you can remove finalizers manually to unblock deletion.
Method 1: kubectl edit
kubectl edit namespace stuck-namespace
# Remove the entries from the finalizers list, save, and exit
Method 2: kubectl patch
# Remove all finalizers from a namespace
kubectl patch namespace stuck-namespace -p '{"metadata":{"finalizers":null}}' --type=merge
# Remove all finalizers from a PV
kubectl patch pv stuck-pv -p '{"metadata":{"finalizers":null}}' --type=merge
Method 3: API call (for stubborn namespaces)
Some namespaces require a direct API call:
kubectl get namespace stuck-namespace -o json | \
jq '.spec.finalizers = []' | \
kubectl replace --raw "/api/v1/namespaces/stuck-namespace/finalize" -f -
Safety Considerations
Removing finalizers bypasses the cleanup that was supposed to happen. Before removing a finalizer, consider:
- Will removing it leave orphaned resources?
- Is there data that needs to be flushed or backed up?
- Is the associated controller simply down and could be restarted?
Try restarting the responsible controller first. Remove finalizers manually only as a last resort.
Key Takeaways
- Finalizers prevent resource deletion until cleanup tasks are complete
- Resources with pending finalizers stay in the Terminating state
- Stuck resources usually mean the responsible controller is not running
- Remove finalizers with
kubectl patchorkubectl editwhen cleanup is not needed - Always investigate why a finalizer is stuck before forcibly removing it