# GKE Idle Load Balancer

> GKE load balancers are declared idle only when every harvested traffic axis (up to 9 covering requests, connections, ingress, and egress) stays below the 0.05 floor on both average and peak with 30 or more days of coverage. Savings equal the forwarding rule's full fixed fee.

Source: https://zop.dev/integrations/gcp/recommendations/gke-idle-load-balancer
Updated: 2026-08-19

---

## Traffic evidence from forwarding rule metrics

none beyond resource.UID/Type; pricing comes from the cost engine (r.pricing[uid]), traffic evidence comes from Cloud Monitoring via the aggregator's forwarding_rule_name-dimensioned harvest (present on all GCP LB monitored-resource types: HTTP(S), L3/L4 passthrough, TCP/SSL proxy).
(GCPGlobalIdleLBRule, resource type gcp-global-lb) via an unexported (*GKEIdleLBRule).evaluate(resource, ruleID) helper parameterized by RuleID. Each rule's exported Evaluate() passes its own rule ID explicitly (Go embedding is not virtual dispatch, so a shared method cannot read r.ID() and expect the embedder's override). gcp-global-lb harvests only a subset of the 9 axes (LBHTTPSRequestCount, LBProxyNewConnections, plus HTTPS bytes/latency, per the aggregator's gcp-global-lb spec); the rule evaluates whichever declared axes are present for the UID and abstains when none is.

## The full forwarding rule fee comes back

concrete-or-abstain (never fabricated/$0). An LB is idle only when every declared traffic axis present for it is below the 0.05 floor on both average and peak (Bug-1: reads each axis by name off the nested metrics view, never a first-wins bare-UID metric) and the representative axis has >= 30 days of measured coverage. Fires only when pricing is known; the saving is the full current forwarding-rule fixed fee (SavingsUSD = cost, OptimizedCostUSD = 0). Abstains (returns nil) when no traffic axis was harvested, any present axis is above the floor, coverage is short, or pricing is absent. Egress (both L3 external/internal) and TCP/SSL-proxy open-connections/ingress/egress axes are required in addition to ingress/new-connections/request-count: a passthrough LB fronting a download-heavy backend has near-zero application-stream ingress while egress is large, and a proxy LB fronting long-lived connections (DB proxy, MQTT, websockets) has near-zero *new* connections while *open* connections and bytes stay high. Either gap alone would misclassify an actively-serving LB as idle.

## Deleting the forwarding rule

1. Verify no traffic is routed through this load balancer in GCP Cloud Monitoring
2. Check if any backend services or instance groups are attached
3. Confirm with the owning team that the load balancer is no longer needed
4. Delete the forwarding rule and associated backend configuration to stop charges

## Why egress and open connections also count

LBHTTPSRequestCount, LBExternalIngressBytes, LBInternalIngressBytes, LBProxyNewConnections, LBExternalEgressBytes, LBInternalEgressBytes, LBProxyOpenConnections, LBProxyEgressBytes, LBProxyIngressBytes (loadbalancing.googleapis.com, 30d, 0.05 floor per axis, checked on both the windowed average AND the full-series peak; was exact ==0 pre-fix)
