Skip to content

Deleted proxies leave their anchors behind #472

Description

@ecv

Summary

Deleting an HTTPProxy leaves its anchor behind on the Karmada hub, and everything the anchor owns stays alive and serving with it.

The anchor is the only thing tying a derived Gateway and HTTPRoute to an upstream object that lives on a different control plane, so nothing else can collect them. Each surviving Gateway then mints a Let's Encrypt Issuer, and one edge cluster has reached 902 Issuers driving 42 requests per second against a fleet baseline of 0.13.

One project namespace on the hub holds 145 anchors today, the oldest from 16 July.

Acceptance criteria

  • An HTTPProxy deleted from a project control plane leaves no anchor on the hub
  • An anchor whose upstream object is already gone is collected without anyone running a tool
  • Anchors stranded before the fix are cleared

What is happening

Read on the Karmada hub on 2026-09-17 at 01:20Z, in ns-45e239ee-7a69-4e44-ba30-48f73f431101, project integration-24be19.

The hub still holds e2e-path-routing-2026-08-01t08-46-39z as both an HTTPRoute and a Gateway, created 1 August, with live ResourceBindings. The project control plane holds nothing from that date, so the upstream HTTPProxy is long gone.

The route carries a single ownerReference to a ConfigMap named anchor-f99c6b9b-907c-4e85-b1d5-d53544c95448, also created 1 August and still present. It carries no data. Its labels name what it stands for: meta.datumapis.com/upstream-cluster-name, upstream-group, upstream-kind, upstream-name and upstream-namespace.

Karmada is behaving correctly throughout. It propagates objects that genuinely exist, so the edge copies are right. The whole cascade is one delete away and that delete never happens.

Why nothing collects it

GatewayDownstreamGCReconciler deletes the anchor, but only for an object it observes going through a finalized deletion:

if dt := obj.GetDeletionTimestamp(); dt.IsZero() || !controllerutil.ContainsFinalizer(&obj, gatewayControllerGCFinalizer) {
	return ctrl.Result{}, nil
}

Miss that window, whether the controller is down, the finalizer is absent, or the event is dropped, and nothing revisits it. The reconciler is keyed on an upstream object that no longer exists, and the anchor carries no owner of its own, so Kubernetes garbage collection has nothing to follow either.

That is the same shape as #233, which proposed a periodic scan over owned resources and was closed in favour of one-off cleanups.

What a responder sees

Ten HTTPRouteStatusWarning alerts are firing in production against two of these routes across five sites, which is how this was found. They are accurate: the backendRef Services really are absent. The objects are broken and they are also immortal.

Related: #182 is the same failure on ResourceClaims, where deleting an HTTPProxy leaves quota consumed. https://github.com/datum-cloud/infra/issues/4684 records the Issuer and rate-limit cost.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Fields

    Priority

    High

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions