<p>I've implemented a controller for Custom Resource (CR) A by <code>controller-runtime</code> lib. CR A is dependent on resource B as</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: CRD.API.Version
kind: A
metadata:
  name: a
spec:
  bName: b
  otherSpecs: ...
</code></pre>
<p>And I add <code>ownerReference</code> on B instances in my controller when A is reconciled, which enables my controller <code>Watches</code> B and would trigger a reconciliation for A if its dependent B is updated. Besides, when A is deleted, related <code>ownerReference</code> on B would be removed:</p>
<pre class="lang-golang prettyprint-override"><code>func (r *MyReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&amp;A{}).
        Watches(&amp;source.Kind{Type: &amp;B{}}, &amp;handler.EnqueueRequestForOwner{OwnerType: &amp;A{}, IsController: false}).
        Complete(r)
}

func (r *MyReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
    a := &amp;A{}
    reconciler.Get(ctx, request.NamespacedName, a)
    b := &amp;B{}
    reconciler.Get(ctx, NamespacedName{Name: a.Spec.bName, Namespace: a.Namespace}, b)
    if !a.DeletionTimestamp.IsZero() {
        clearOwnerReference(b)
        reconciler.Update(ctx, b)
        return ...
    }
    setOwnerReference(b.OwnerReference, a)
    reconciler.Update(ctx, b)
    // Other reconciliation logic
}
</code></pre>
<p>But Kubernetes API server acts more quickly: it detects B is orphan and deletes B, i.e., GC.</p>
<p>I also tried to add finalizer on B. But when my controller removes both <code>ownerReference</code> and <code>finalizers</code> from B, it's gone, since it's already been marked as deleted.</p>
<p>Any other config on B can be utilized to prevent such cascading deletion? Or any best practice to handle such dependency?</p>

<p>You will need to add a finalizer to A, so that when A is deleted, in the finalizer logic you remove the OwnerReference from B. This way A's deletion is not orphaning B in Kubernetes GC's eyes, as when A is deleted after the finalizer logic, it does not own anything.</p>
