✓
ASP.NET Core

Kubernetes Resource Requests and Limits for ASP.NET Core: Avoid Throttling and OOM Kills

Advertisement
Ad space
.NET

Kubernetes Resource Requests and Limits for ASP.NET Core: Avoid Throttling and OOM Kills

Moving an ASP.NET Core API into Kubernetes does not make capacity planning disappear; it makes the contract explicit. CPU and memory requests tell the scheduler what a Pod needs to be placed. Limits constrain what the running container may consume. A copied manifest can therefore create either a Pending workload, avoidable latency from CPU throttling, or a process terminated under memory pressure.

This guide gives a measured starting point for a .NET API and a repeatable way to tune it. It complements the ASP.NET Core Docker tutorial and the practical health-check guide.

Requests schedule; limits enforce

Kubernetes schedules a Pod using its requests, not its momentary usage. A CPU limit is enforced by throttling; a memory limit can result in an OOM kill when the node is under memory pressure. That difference matters for APIs: CPU throttling can show up as a rising tail latency, while a memory kill turns an in-flight request into a restart.

Start from production-like traffic, not a guess. Record steady and peak working set, allocation rate, GC behavior, CPU use, request latency, and dependency wait time. The application may be waiting on a database or an upstream HTTP service rather than needing more CPU.

A conservative Deployment baseline

The following is an example baseline, not a universal sizing recommendation. The readiness endpoint should only report ready after dependencies required to serve traffic are usable; liveness should remain inexpensive and avoid turning a transient database outage into a restart loop.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: orders-api
  template:
    metadata:
      labels:
        app: orders-api
    spec:
      containers:
        - name: api
          image: registry.example.com/orders-api:2026.11.04
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 15

Measure before changing the numbers

Load test a representative mix: successful requests, validation failures, authenticated paths, slow dependencies, and payloads near the accepted maximum. Compare p50, p95, and p99 latency with CPU usage and throttling. Inspect restart counts and termination reasons. Then change one resource dimension at a time and repeat.

Memory needs headroom for managed heap growth, native allocations, TLS buffers, request bodies, libraries, and the operating system. Treat a container that regularly approaches its memory limit as an incident candidate; raising a limit without finding the allocation source merely delays failure. For CPU, assess the latency cost of a cap rather than assuming a higher limit improves throughput.

Common mistakes

  • Setting only a limit: Kubernetes may default the request to that limit, making scheduling unexpectedly expensive.
  • Using 400m for memory: lowercase m is millibytes; use an intentional unit such as 400Mi.
  • Making readiness call every downstream dependency with a slow timeout.
  • Scaling replicas without checking database pools, queues, and upstream rate budgets.
  • Using local observation as capacity evidence when production traffic has different payloads and concurrency.

Production checklist

  • Set CPU and memory requests for every application container, including sidecars.
  • Alert on restart reason, OOM kills, CPU throttling, saturation, and tail latency together.
  • Use a rolling deployment that keeps enough ready replicas for the traffic budget.
  • Keep image configuration and secrets out of the manifest; inject configuration through the platform’s secure mechanism.
  • Review namespace quotas and limit ranges with the cluster team before rollout.

Conclusion

Resources are an operational hypothesis. Publish a measured baseline, validate it under realistic load, and revisit it after code, traffic, or dependency changes. For the delivery sequence around this deployment, continue with the .NET and ASP.NET Core learning track.

Sources

Sponsored
Ad space
🎉 Finished reading. Nice work!

Leave a Reply

Your email address will not be published. Required fields are marked *