Kubernetes
Kubernetes Ingress Cleanup: Remove Routes With No Traffic
Kubernetes ingress cleanup starts when a hostname looks abandoned but nobody is sure whether it is safe to remove. The route may have no visible traffic, point at a service that was replaced months ago, or still exist only because an environment was cloned and never fully retired. It can also be the path for a low-volume customer, a payment callback, a health probe, a partner allowlist, or an emergency-only admin workflow.
The goal is not to delete every quiet route. The goal is to prove which Ingress objects, host rules, TLS secrets, DNS records, and backend services still have a current reason to exist. A good cleanup review leaves a small decision record: what hostnames were checked, which backends they route to, what traffic evidence was used, who approved the change, and what to watch after the reversible step.
This note is for platform engineers, SREs, and application owners who need to reduce stale Kubernetes routes without turning “no traffic” into the first real test of whether a route mattered.
Key Takeaways
- Review Ingress cleanup at the hostname and path level, not just the object level.
- Compare controller traffic, DNS records, TLS certificates, backend services, and Git manifests before removing a route.
- Treat webhooks, partner callbacks, customer-specific hostnames, and incident-only admin paths as quiet-by-design until proven otherwise.
- Use a reversible first move such as redirecting, removing DNS from a low-risk environment, or disabling a preview route before deleting manifests.
- Prevent recurrence by requiring expiry metadata and route ownership during environment creation.
Build a Route Inventory
Start with the route users can hit: scheme, hostname, path, ingress class, namespace, service, and port. Kubernetes object names are often misleading because one Ingress can carry several host rules, and one hostname can be split across multiple path rules.
| Inventory field | Why it matters for ingress cleanup |
|---|---|
| Hostname | DNS, certificates, customer docs, and bookmarks depend on this string |
| Path rule | A quiet /admin or /webhook path can matter even if / is obsolete |
| Ingress class | Different controllers may write metrics and load balancer state differently |
| Backend service and port | The route may be stale while the service is still used internally |
| TLS secret | Certificate renewal or secret ownership can reveal a still-active owner |
| Source manifest | Cleanup should remove the declared route, not only the live object |
| External dependency | DNS records, partner allowlists, OAuth callbacks, and webhook settings can outlive app traffic |
Keep the first pass small. Pick one cluster or one namespace family, export the routes, and group candidates by owner. A route without an owner is not automatically removable, but it is automatically a cleanup candidate because nobody can explain its current purpose.
Evidence That a Route Is Actually Unused
Ingress cleanup needs evidence from both Kubernetes and the edge. The cluster can tell you that a route exists and which service it points to. The ingress controller, load balancer, CDN, DNS provider, and application logs usually tell you whether anyone still reaches it.
| Evidence check | Strong cleanup signal | False positive to watch |
|---|---|---|
| Controller request metrics | No requests for the host and path across a full business cycle | Metrics labels changed after a controller upgrade |
| Access logs | No 2xx, 3xx, 4xx, or webhook-style requests for the hostname | Logs are sampled, disabled, or retained for too short a window |
| DNS records | Hostname no longer resolves or points at an old ingress address | Internal DNS or partner DNS still points to the route |
| Backend service endpoints | Service has no endpoints or only obsolete deployments | Service is intentionally scaled to zero outside job windows |
| Git history | Route was removed from app docs or replaced by a newer hostname | A rollback branch or release train still references the old host |
| TLS certificate usage | Certificate is expired, unmanaged, or shared only by stale hosts | Wildcard certificates hide route-specific use |
Do not let one signal carry the decision. “No requests” is useful, but it is weak if the route is a monthly report callback. “No endpoints” is useful, but it is weak if the route intentionally wakes a service through a controller, queue, or manual runbook.
Read-Only Kubectl Checks
Use kubectl to map the live route to its backend before you ask an owner to approve cleanup. The commands below are read-only and are meant to create a review list, not a deletion pipeline.
kubectl get ingress --all-namespaces -o wide
kubectl describe ingress -n $NAMESPACE $INGRESS_NAME
kubectl get service -n $NAMESPACE $SERVICE_NAME -o wide
kubectl get endpointslice -n $NAMESPACE -l kubernetes.io/service-name=$SERVICE_NAME
kubectl get secret -n $NAMESPACE $TLS_SECRET -o jsonpath='{.type}{"\n"}'
The output proves which host rules exist, which services receive traffic, whether endpoint slices currently back the service, and what TLS secret type is attached. It does not prove that traffic is absent. Pair it with ingress controller metrics, access logs, DNS checks, and owner confirmation.
If your cluster still relies on classic Endpoints rather than EndpointSlice for a specific workflow, check that object too. The important part is to prove the backend path, not to depend on one resource kind forever.
Hostnames That Need Extra Patience
Some routes are supposed to be quiet. Slow down when the hostname or path looks like any of these:
- Webhook callbacks from payment processors, identity providers, Git hosting, CI systems, or marketplace integrations.
- Customer-specific hostnames that only receive traffic during onboarding, audits, renewals, or support incidents.
- Admin, break-glass, or migration paths that are intentionally absent from normal user journeys.
- Preview and review-app routes referenced from old pull requests, QA scripts, or external bug reports.
- Blue-green, canary, or rollback routes that are dormant until a release goes wrong.
The reversible step for these routes is usually not deletion. It may be owner repair, adding route metadata, shortening DNS TTL, documenting a replacement URL, or moving the route behind an explicit approval gate.
Choose the First Reversible Move
Ingress cleanup has several levels. Pick the smallest move that tests the cleanup decision without making recovery depend on memory.
| Cleanup move | When to use it | What to watch |
|---|---|---|
| Add owner and expiry annotations | The route may be real, but accountability is missing | Owner response and expiry review date |
| Mark the route deprecated in docs | Users may still discover the old hostname | Support tickets, redirects, and search traffic |
| Remove DNS for non-production hostnames | The app route is clearly obsolete and easy to restore | NXDOMAIN reports, CI failures, QA complaints |
| Redirect to the replacement route | Human users may still follow old links | Redirect volume and status codes |
| Remove one path rule | Only part of the host appears stale | 404s, webhook retries, and application errors |
| Delete the Ingress manifest | Host, path, backend, DNS, and owners all agree | Controller events, load balancer changes, and synthetic checks |
Write the rollback before the final removal. For Git-managed clusters, that is usually a revert of the manifest change plus any DNS or certificate restoration steps. For imperative legacy changes, capture the current object YAML before editing so the team knows what state existed at approval time.
Common Ingress Cleanup Mistakes
The easiest mistake is deleting the Kubernetes object while leaving DNS, certificates, or external callbacks behind. That turns a clear route into a confusing failure mode: users still resolve a hostname, but the cluster no longer has a rule for it.
Another mistake is treating all 404s as proof that a route is unused. A webhook endpoint may return 404 for unauthenticated probes and 200 only for signed provider calls. A partner callback may use a path that does not appear in browser traffic. A health checker may hit a route from an internal network that is absent from public logs.
A third mistake is removing an old route without updating the creation workflow that produced it. Preview environments, demo namespaces, and temporary customer migrations should require expiry metadata at creation time. Otherwise every cleanup pass becomes a manual archaeology project.
Prevention Rules for New Routes
Prevention should change how routes are created. Adding an owner label after the fact helps the next review, but it does not stop stale hostnames from appearing.
Require these fields in the Ingress creation path:
| Required field | Example | Why it prevents stale ingress |
|---|---|---|
| Owner | platform.example.com/owner: checkout | Gives cleanup reviewers a team to ask |
| Route purpose | platform.example.com/purpose: partner-webhook | Separates rare-but-real traffic from clutter |
| Expiry | platform.example.com/expires: 2026-06-30 | Forces temporary routes back into review |
| Replacement URL | platform.example.com/replaced-by: https://app.example.com | Makes redirects and docs updates easier |
| Source ticket | platform.example.com/request: ENG-1234 | Preserves why the route was created |
For temporary environments, make the route expire with the environment rather than asking cleanup reviewers to rediscover the lifecycle later. For production routes, require a service catalog entry, alert owner, and documented rollback path before the route is accepted.
Decision Record
Use a compact record for each removed hostname or high-risk path.
| Field | Example entry |
|---|---|
| Candidate | old-api.example.com /v1/webhook in payments-prod |
| Why it looked stale | No controller requests in 60 days and replacement route exists |
| Evidence checked | Ingress rule, backend service, endpoint slices, DNS, TLS secret, controller metrics, provider callback settings |
| Owner decision | Payments approved redirect for 14 days before manifest deletion |
| First move | Redirect old host to replacement route and watch callback retries |
| Watch signal | Provider retry dashboard, ingress 4xx/5xx by host, support tickets |
| Final action | Remove DNS and Ingress manifest after review window |
| Prevention rule | Temporary partner routes require expiry and callback owner |
This format is short enough to live in a pull request, but detailed enough for the next engineer to understand why the route disappeared.
FAQ
How long should we watch an Ingress route before deleting it?
Use a window long enough to include release cycles, customer schedules, batch callbacks, and incident workflows. Thirty days may be enough for a preview route. Production webhooks, partner routes, and customer-specific hostnames often need a longer window or explicit confirmation from the external system owner.
Is zero traffic enough to remove an Ingress?
No. Zero visible traffic is a candidate signal, not a removal decision. Confirm DNS, controller metrics, access logs, backend services, external callbacks, TLS ownership, and source manifests before deletion.
Should stale routes be redirected or deleted?
Redirect human-facing routes when users may still have bookmarks, docs, or search results. Delete routes when the hostname and path have no current consumer, no replacement journey is needed, and the rollback path is clear. Webhooks usually need provider-side updates rather than simple redirects.
What should the cleanup pull request include?
Include the hostname, path rules, backend service, evidence window, owner approval, DNS or certificate changes, rollback steps, and watch signals. Link to the broader cleanup library when the route cleanup is part of a larger Kubernetes or infrastructure review.