cd /news/artificial-intelligence/kubernetes-cost-governance-policies-… · home topics artificial-intelligence article
[ARTICLE · art-68648] src=cast.ai ↗ pub= topic=artificial-intelligence verified=true sentiment=↓ negative

Kubernetes Cost Governance: Policies That Stop Waste Before It Ships

A Cast AI report finds 69% of Kubernetes clusters are CPU-overprovisioned in 2026, up from 40% in 2024, with average CPU utilization at 8%, and the company advocates for admission-time policies like ResourceQuotas and LimitRanges over quarterly cleanup campaigns to structurally prevent waste.

read13 min views1 publishedJul 22, 2026
Kubernetes Cost Governance: Policies That Stop Waste Before It Ships
Image: Cast (auto-discovered)

Key takeaways #

  • 69% of Kubernetes clusters are CPU-overprovisioned in 2026, up from 40% in 2024. Quarterly cleanup campaigns don’t fix the structural causes of that overprovisioning.
  • ResourceQuotas cap aggregate namespace consumption across CPU, memory, and object counts. LimitRanges inject per-container defaults and enforce min/max bounds at admission time.
  • Deploy LimitRange before or alongside ResourceQuota. The LimitRange admission controller runs first, and pods without explicit resource declarations receive HTTP 403 errors if no LimitRange is present to supply defaults.
  • Admission webhooks (Kyverno or OPA Gatekeeper) validate and mutate resources at admission time, before they persist to etcd. Both tools support audit mode for safe brownfield migration.
  • Shift-left tooling (Conftest, Kyverno CLI, Argo CD) catches policy violations at PR time, when correction costs the least.
  • Cast AI complements governance policies by rightsizing actual requests and limits to match observed workload behavior, recovering headroom that policies alone cannot reclaim.

Why policies beat cleanup #

Most platform teams have run a cost cleanup campaign. They audit running workloads, find containers with request values that dwarf actual usage, patch the definitions, and watch the bill drop. Then, six months later, the problem is back.

The reason is structural. Helm chart authors don’t know your workload. They pick conservative resource defaults that won’t break on deploy, and those defaults ship to production. Teams move on to the next feature and never revisit the resource definitions. Cost is invisible at the team level because most organizations still don’t implement chargeback: according to the FinOps Foundation’s 2025 report, only 14% of teams have it in place.

The numbers compound over time. According to the Cast AI 2026 State of Kubernetes Optimization Report, 69% of clusters are CPU-overprovisioned today, up from 40% in 2024. Memory overprovisioning is even worse, with 79% of clusters affected. Average CPU utilization across the industry sits at 8%. At that utilization rate, a $50,000/month cluster wastes roughly $46,000/month. A CNCF FinOps Microsurvey found that 49% of organizations saw cloud spend increase after migrating to Kubernetes, and 70% of those cited overprovisioning as the cause.

Cleanup doesn’t change those numbers because it doesn’t change the process that produces them. Policies do. Instead of auditing running workloads every quarter, you define guardrails at the point of admission. A team cannot ship a pod without resource limits because the cluster rejects it. A namespace cannot consume more than its allocated CPU budget because the quota blocks it. The discipline becomes structural, not aspirational.

For a broader view of cost control at the Kubernetes layer, the Kubernetes FinOps guide covers budgeting, showback, and chargeback alongside policy enforcement. When costs spike unexpectedly despite policies in place, cost anomaly detection gives you the signal before the bill arrives.

ResourceQuotas and LimitRanges #

Kubernetes ships with two built-in admission controllers that handle most of the heavy lifting for namespace-level cost governance. They are complementary, and they need to be deployed in the right order.

ResourceQuota: aggregate namespace caps

A ResourceQuota defines aggregate limits at the namespace level. You specify how much total CPU and memory the namespace can request and limit, plus object count caps for pods, secrets, ConfigMaps, and other API objects. The object count caps matter more than most teams realize. Runaway Helm releases stack up secrets on every upgrade, and the Kubernetes API server pays the cost of storing and serving them.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "4"          # Total CPU requests allowed in this namespace
    requests.memory: "8Gi"     # Total memory requests allowed
    limits.cpu: "8"            # Total CPU limits allowed (burst headroom above requests)
    limits.memory: "16Gi"      # Total memory limits allowed
    pods: "20"                 # Hard cap on pod count prevents runaway scaling
    secrets: "20"              # Protects API server from runaway Helm secrets

ResourceQuotas apply to new resource creation only – adding a quota to an existing namespace does not terminate running pods that exceed it. This makes quota enforcement safe to roll out incrementally: existing workloads keep running while you measure their consumption and calibrate the quota values before flipping to strict enforcement.

LimitRange: per-container defaults and bounds

A LimitRange operates at the container level. It injects default requests and limits for containers that don’t declare them, and it enforces minimum and maximum bounds per container. This is the mechanism that prevents a single container from claiming 64 CPUs on a shared cluster.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-alpha
spec:
  limits:
  - type: Container
    default:              # Injected when a container omits limits entirely
      cpu: "500m"
      memory: "256Mi"
    defaultRequest:       # Injected when a container omits requests entirely
      cpu: "100m"
      memory: "128Mi"
    max:                  # Hard ceiling per container; admission rejects anything above
      cpu: "2"
      memory: "2Gi"
    min:                  # Floor per container; prevents zero-resource declarations
      cpu: "50m"
      memory: "64Mi"

The ordering constraint and the HPA trap

There is a critical ordering constraint to get right. The LimitRange admission controller runs before the ResourceQuota check. If you deploy a ResourceQuota without a LimitRange and a pod arrives without explicit resource declarations, the API server returns HTTP 403 because it cannot compute whether the pod fits within the quota. Deploy LimitRange first, or apply both objects in the same operation.

There is also a less-obvious interaction with the Horizontal Pod Autoscaler. When a namespace quota is exhausted and an HPA tries to scale a deployment, the HPA emits an AbleToScale: False

condition and the ReplicaSet controller records FailedCreate

events – but the Deployment itself shows no obvious error status. Operators often miss quota exhaustion because it surfaces in events, not in kubectl get deployments

output. Add quota-exhaustion alerting to your monitoring setup so the signal is clear and actionable.

For a detailed configuration reference covering scope selectors, priority class quotas, and additional edge cases, see the ResourceQuotas and LimitRanges deep dive. This post stays at the conceptual level; that one has the full YAML reference.

Before you enforce

Before rolling out ResourceQuotas to existing namespaces, run a pre-enforcement audit:

kubectl describe resourcequota -n <namespace>
kubectl describe limitrange -n <namespace>
kubectl get pods -n <namespace> -o json | jq '.items[].spec.containers[].resources'

The first two commands show existing quota and range boundaries. The third surfaces every container’s current resource declarations, including empty {}

entries that a LimitRange or admission policy will reject. Fix empty declarations before enforcing.

Admission policies: Gatekeeper and Kyverno #

Built-in admission controllers handle aggregate caps and default injection. Admission webhooks handle policy logic: custom rules that validate or mutate resources at admission time, before they persist to etcd. The key distinction is runtime enforcement versus admission-time enforcement. A running pod that violates a rule is already costing money. An admission webhook blocks it before it runs.

Kyverno: YAML-native and platform-friendly

Kyverno uses the same YAML patterns platform teams already know – and that’s not a minor convenience. Platform teams maintain dozens of tools, onboard new engineers constantly, and can’t afford a steep policy-language learning curve. A policy written in Kyverno looks like any other Kubernetes manifest: reviewable in a PR, testable with a CLI, deployable with kubectl. There’s no new language to learn and no external runtime to operate.

Kyverno supports three policy modes: validation (reject non-compliant resources), mutation (modify resources at admission time), and generation (create resources automatically). The generation mode is particularly useful for cost governance: configure Kyverno to auto-create a ResourceQuota and LimitRange whenever a new namespace is created, and every namespace ships with guardrails from day one without requiring manual setup per team.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-for-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "CPU and memory resource limits are required on all containers."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    cpu: "?*"
                    memory: "?*"

Set validationFailureAction: Audit

first in brownfield clusters. Audit mode writes violations to PolicyReport resources without blocking anything, giving you a clear picture of what needs fixing before you flip to Enforce

.

OPA Gatekeeper: Rego power for cross-stack orgs

OPA Gatekeeper uses Rego, a general-purpose policy language. Rego has a steeper learning curve than Kyverno’s YAML patterns, but the payoff is portability – and portability matters at scale. The same Rego rule that enforces CPU limit requirements in your Kubernetes admission controller can run via Conftest against Helm charts in CI, against Terraform plans in a pre-apply check, and against any structured file your pipeline produces. For organizations managing policy consistency across multiple infrastructure layers, writing Rego once and running it everywhere eliminates the drift that comes from maintaining separate policy definitions per tool.

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlimits
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLimits
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlimits

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.cpu
          msg := sprintf("Container '%v' is missing CPU limits.", [container.name])
        }

        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.memory
          msg := sprintf("Container '%v' is missing memory limits.", [container.name])
        }
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLimits
metadata:
  name: require-container-limits
spec:
  enforcementAction: deny    # Change to "warn" for audit mode
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

Gatekeeper’s audit controller scans live cluster state on a schedule and writes violations to the Constraint resource’s .status.violations

field. Each violation entry includes the violating resource’s name, namespace, and the policy message. To surface these as Kubernetes-native PolicyReport objects, install the policy-reporter integration with the Gatekeeper adapter – this is not included in a default Gatekeeper installation.

One production decision both tools require: set the webhook’s failurePolicy

. When failurePolicy: Fail

is configured, any admission webhook timeout or crash blocks ALL new workloads in the namespace – even unrelated ones. When set to Ignore

, a webhook failure silently bypasses all policies. Most teams start with Fail

on non-production namespaces and Ignore

on production until the webhook is proven stable, then flip to Fail

cluster-wide. Kyverno defaults to Fail

; Gatekeeper defaults to Fail

for the audit controller and Ignore

for the validating webhook.

What developers should do when blocked

When a policy blocks a deployment, developers will see an error message in their CI/CD output or from kubectl: “CPU and memory resource limits are required on all containers.” The fix is always in the workload manifest: add the missing resource declarations. For teams with workloads that genuinely need elevated resources, establish a documented exception process: file a request with the platform team, justify the request with production metrics, and update the LimitRange max bound or ResourceQuota for that namespace. Avoid disabling policies globally to unblock individual deployments.

Policy as code in CI/CD #

Admission webhooks catch violations at deploy time. Shift-left tooling catches them at PR time, which is significantly cheaper for everyone involved. A developer who gets a rejection at kubectl apply

has already built and pushed an image. A developer who gets a rejection in CI still has context and can fix the manifest before it merges.

Three tools worth knowing

Conftest runs OPA/Rego policies against any structured file format, including Kubernetes manifests and Helm-rendered templates. Add it as a CI step and every manifest gets policy-checked before it merges. It reuses the same Rego policies you’ve already written for Gatekeeper, so there’s no duplication.

Kyverno CLI (kyverno test

) runs Kyverno policies against local manifests without requiring a live cluster. It integrates cleanly with GitHub Actions, GitLab CI, or any pipeline that can run a container. Teams get policy feedback in the same PR flow where they write code.

Argo CD with Kyverno enforces policies at GitOps sync time. If a manifest in the repo violates a policy, the sync fails before the resource reaches the cluster. This is the tightest shift-left integration for GitOps-based platforms.

Brownfield migration path

For existing clusters, the migration path is straightforward. First, deploy your admission policies in audit mode. Then, generate PolicyReports and fix violations namespace by namespace, starting with the highest-spend namespaces. Finally, switch to enforce mode once violations drop to zero. This approach avoids the day-one incident where new enforcement breaks a production workload that was already running.

The same audit-first pattern applies to ResourceQuotas. Set initial quota values generously based on current peak consumption, then tighten them incrementally as teams right-size their workloads. A quota that immediately blocks production traffic is worse than no quota at all.

How Cast AI addresses this #

Governance policies define what the cluster will accept. They prevent teams from shipping pods without resource declarations and prevent namespaces from consuming more than their budget. However, policies cannot recover waste that already exists inside those limits.

A container with a CPU request of 500m but consistent production usage of 80m wastes 420m per instance. Multiply that across hundreds of containers and the waste compounds quickly. Cast AI’s workload rightsizing engine analyzes actual CPU and memory consumption patterns from production metrics and automatically adjusts requests and limits to match observed behavior. The result is that the floor your policies enforce becomes progressively tighter without requiring manual audit cycles.

Governance policies create the structural constraint: no pod ships without resource limits, no namespace exceeds its CPU budget. Cast AI eliminates the slack within those constraints by continuously right-sizing the values. Before enabling rightsizing, use the Available Savings panel to see what Cast AI estimates you could recover from your current cluster. Connect your cluster to Cast AI to see rightsizing opportunities and gaps where namespaces lack ResourceQuotas or LimitRanges.

Conclusion #

Kubernetes cost governance policies work because they fix the process, not just the numbers. ResourceQuotas and LimitRanges enforce consumption bounds at the namespace and container level. Admission policies (Kyverno or OPA Gatekeeper) block non-compliant configurations before they run. Shift-left tooling extends that enforcement to PR time, where correction costs the least.

For the full governance picture, the Kubernetes FinOps guide covers budgeting, showback, and chargeback alongside policy enforcement. For deep YAML configuration on quota mechanics, the detailed configuration reference covers scope selectors, priority class quotas, and admission controller ordering in full.

Frequently Asked Questions #

What are Kubernetes cost governance policies? Kubernetes cost governance policies are rules enforced at admission time that control how resources are provisioned and consumed across the cluster. They include ResourceQuotas (aggregate namespace caps), LimitRanges (per-container defaults and bounds), and admission webhook policies from tools like Kyverno or OPA Gatekeeper. Together, they prevent waste before it ships by rejecting non-compliant resource configurations at the point of admission, not after the bill arrives.

How do ResourceQuotas help control Kubernetes cost? ResourceQuotas cap the total CPU, memory, and object count a namespace can consume. When a pod request would push the namespace over its quota, the API server rejects it with a Forbidden error. This prevents any single team or application from exhausting shared cluster resources and makes cost boundaries enforceable, not aspirational. For quota configuration details and kubectl commands for brownfield clusters, see the full ResourceQuotas and LimitRanges reference.

OPA Gatekeeper vs Kyverno: which is better for cost governance? Kyverno is the better starting point for most platform teams. It uses native Kubernetes YAML, requires no new language to learn, and supports mutation (injecting defaults) and resource generation (auto-creating LimitRanges on new namespaces) out of the box. OPA Gatekeeper is the right choice when you need cross-platform policy reuse: the same Rego rules that enforce limits in Gatekeeper can run via Conftest against Helm charts and Terraform plans in CI pipelines.

How do I enforce resource request limits in Kubernetes? Deploy a LimitRange first to inject default requests and limits for containers that omit them. Then deploy a ResourceQuota to cap total namespace consumption. Layer a Kyverno ClusterPolicy or OPA Gatekeeper Constraint to reject pods that still lack explicit declarations. Finally, add Kyverno CLI or Conftest to your CI pipeline to catch violations at pull-request time. This four-layer approach shifts enforcement as far left as possible.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @cast ai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/kubernetes-cost-gove…] indexed:0 read:13min 2026-07-22 ·