Cloud Run Dev/Test Service Has Min Instances > 0
What does ZopNight detect here?
Cloud Run services with dev/test evidence and minInstances above 0 are told to set --min-instances=0. Savings price the always-warm capacity being removed: minInstances times the per-second vCPU and memory warm rates times seconds per month, capped at cost; a prod label or missing rates abstains.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1209 |
| Category | rightsizing |
| Severity | low |
| Metric | none — pure configuration read |
| Source | cloudrun_min_instances.go |
Where it applies
Where minInstances and the env label live
- resource.Metadata: minInstances (via getMetaFloat; producer asset_inventory.go:3159 enrichGCPCloudRun writes it from the autoscaling.knative.dev/minScale annotation, the same key cloudrun_idle.go uses). The prior tag: min_instances was a dead contract (item T0295).
- resource.Tags: env tag (env/environment/stage/tier): authoritative prod veto (isProdEnvTag) AND positive dev/test evidence (isDevTestEnvTag). Kept for parity with providers where env genuinely lives in Tags, but on Cloud Run the discoverer never writes env into Tags (only max_concurrency), so this reader is always empty on real GCP data.
- resource.Metadata: nested labels.env (env/environment/stage/tier), the actual GCP producer sink (asset_inventory.go genericEnrichGCPLabels writes customer labels under Metadata[“labels”], never Tags). Read via isProdEnvLabel/isDevTestEnvLabel (gke_spot_nodepool.go helpers), OR’d with the Tags-based checks above so the prod veto and dev/test evidence gates are no longer dead on live Cloud Run data.
- resource.Name: dev/test pattern (dev, test, qa, staging, sandbox): positive dev/test evidence (isDevTestName), but no longer name-sole: a prod-looking name or env=prod tag/label vetoes first.
- resource.Metadata: cpu + memory (asset_inventory.go:3706/3710, Knative quantity strings)
- PricingAware + SKURatesAware: per-resource monthly cost + cloudrun-cpu-second / cloudrun-mem-gib-second per-second warm-capacity rates
Pricing the always-warm capacity you remove
concrete-or-abstain (cost-driven rightsizing). The prior advisory/SavingsUSD=0 (and earlier 0.30 fraction) posture is removed. savings = minInstances × (vcpu×cpuSecondRate + memGiB×memSecondRate) × secondsPerMonth, capped at cost, the identical idle-warm formula sibling RC-149 uses on the same resource type and minInstances key; scaling min→0 removes exactly this always-allocated warm component, request-served capacity unaffected. Abstains (returns nil, never $0) when not dev/test, minInstances ≤ 0, no/zero pricing, vCPU/memory absent/unparseable, or either per-second rate missing.
Setting min instances back to zero
- Update the Cloud Run service to set —min-instances=0