Monitoring a Kubernetes-hosted .NET application often starts with a simple question: how much CPU and memory is each Pod using?

Developers commonly answer that question with:

kubectl top pods

Behind this command is the Kubernetes resource metrics API, exposed through the metrics.k8s.io API group.

Kubernetes 1.37 promotes the Resource Metrics API to stable, providing a more mature API surface for accessing CPU and memory usage for Nodes and Pods. The API is served by the Metrics Server rather than directly by the Kubernetes API server.

For .NET teams, this matters when building dashboards, autoscaling workflows, deployment diagnostics, or internal tools that need Kubernetes resource-usage information without depending on the human-readable output of kubectl top.

What Is the metrics.k8s.io API?

The Resource Metrics API provides resource usage information for Kubernetes Nodes and Pods.

Its API group is:

metrics.k8s.io

The two primary resources are:

nodes
pods

A simplified architecture looks like this:

.NET Application
      |
      v
    Pod
      |
      v
 Metrics Server
      |
      v
metrics.k8s.io API
      |
      v
Kubernetes clients / HPA

The API provides CPU and memory metrics, which are useful for short-term resource usage information. It is not intended to replace a full monitoring system for long-term historical metrics.

Why This Matters for .NET Developers

A .NET application's resource behavior can change significantly under different workloads.

For example:

Low traffic
    ↓
CPU: 50m
Memory: 180Mi

High traffic
    ↓
CPU: 700m
Memory: 420Mi

If the Pod has:

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "512Mi"

the actual usage can be compared with the configured requests and limits.

This helps answer questions such as:

The Resource Metrics Pipeline

It is important to understand where the numbers come from.

A simplified Kubernetes resource-metrics pipeline is:

Kubelet
   |
   | Resource usage
   v
Metrics Server
   |
   | Aggregated metrics API
   v
metrics.k8s.io
   |
   +--> kubectl top
   |
   +--> HPA
   |
   +--> Custom clients

Metrics Server collects resource metrics from Kubelets and exposes them through the Kubernetes API aggregation layer.

This distinction is important when troubleshooting.

If:

kubectl top pods

does not return data, the .NET application may be completely healthy. The problem could instead be in Metrics Server, Kubelet metrics collection, API aggregation, authentication, or networking.

Checking Pod Metrics

The easiest way to inspect resource metrics is:

kubectl top pods

For a specific namespace:

kubectl top pods -n production

You may see output similar to:

NAME                         CPU(cores)   MEMORY(bytes)
orders-api-7c8f7b9d5f-a1b2c  120m         220Mi
orders-api-7c8f7b9d5f-c3d4e  135m         235Mi

These values provide a current resource-usage view.

For a production monitoring system, however, do not treat kubectl top as your historical monitoring solution.

Accessing the API Directly

The Resource Metrics API can be queried through the Kubernetes API server.

For example:

kubectl get --raw \
  "/apis/metrics.k8s.io/v1beta1/namespaces/default/pods"

The API version available in a particular cluster should be checked rather than hardcoded into tooling.

The important point is that applications can consume structured API responses instead of parsing CLI output.

A response contains resource usage for Pods, including CPU and memory information.

Calling Kubernetes Metrics From .NET

A .NET service that has appropriate Kubernetes API permissions can query the resource metrics API.

A simple approach is to use HttpClient against the Kubernetes API server.

For example:

using System.Net.Http.Headers;

public sealed class KubernetesMetricsClient
{
    private readonly HttpClient _httpClient;

    public KubernetesMetricsClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> GetPodMetricsAsync(
        string namespaceName,
        CancellationToken cancellationToken)
    {
        var path =
            $"/apis/metrics.k8s.io/v1beta1/" +
            $"namespaces/{namespaceName}/pods";

        using var response =
            await _httpClient.GetAsync(
                path,
                cancellationToken);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsStringAsync(
            cancellationToken);
    }
}

In a real application, the client should deserialize the response into typed models rather than returning a raw string.

More importantly, the application needs Kubernetes authentication and authorization configured correctly.

Do Not Give Applications Excessive Kubernetes Permissions

A monitoring application should follow the principle of least privilege.

For example, if it only needs to read Pod metrics, its Kubernetes permissions should not include unrelated operations such as:

create deployments
delete pods
update secrets
patch nodes

A minimal read-only permission model is preferable.

A conceptual RBAC configuration might look like:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-metrics-reader
rules:
  - apiGroups:
      - metrics.k8s.io
    resources:
      - pods
    verbs:
      - get
      - list

The exact RBAC scope should be reduced further when namespace-level access is sufficient.

Metrics API vs .NET Application Metrics

One of the most important distinctions is that metrics.k8s.io and .NET application metrics measure different things.

Monitoring LayerExample DataMain Purpose
metrics.k8s.ioPod CPU, memoryKubernetes resource usage
.NET runtime metricsGC heap, allocationsRuntime behavior
ASP.NET Core metricsRequests, latencyApplication behavior
Database metricsConnections, query latencyData-layer behavior
Full monitoring platformHistorical time seriesLong-term observability

For example, a Pod might show:

CPU: 500m
Memory: 400Mi

but that does not explain why memory increased.

.NET runtime metrics may reveal:

GC heap → increasing
Allocation rate → increasing
Gen 2 collections → increasing

Together, the two layers provide much more useful information.

Resource Metrics and Horizontal Pod Autoscaling

The Horizontal Pod Autoscaler can use resource metrics to adjust replica counts.

For example:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: orders-api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: orders-api
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

The HPA needs resource metrics to make this calculation.

This creates the following flow:

.NET Pods
   |
   v
Kubelet
   |
   v
Metrics Server
   |
   v
metrics.k8s.io
   |
   v
HPA
   |
   v
Deployment replica count

If the resource metrics pipeline is broken, an HPA using those metrics may not behave as expected. Kubernetes documents the Resource Metrics API as a source for CPU and memory metrics used by components such as HPA.

Why Resource Requests Matter

CPU utilization-based HPA calculations can be based on the Pod's resource requests.

Consider:

resources:
  requests:
    cpu: "500m"

If the container uses:

250m

that represents:

50% of requested CPU

Now consider:

resources:
  requests:
    cpu: "250m"

The same 250m usage represents:

100% of requested CPU

The application has not changed, but the HPA calculation can be affected because the request changed.

This is why resource requests should represent realistic workload requirements.

Monitoring Memory for .NET Applications

Memory deserves special attention.

Suppose a Pod has:

resources:
  limits:
    memory: "512Mi"

and kubectl top reports:

MEMORY
470Mi

That should trigger investigation even if the application still appears healthy.

The .NET process may have:

Managed heap
Native memory
Thread stacks
JIT/runtime memory
Buffers

all contributing to total container memory.

Do not assume that a GC heap measurement alone represents the entire container memory footprint.

Troubleshooting metrics.k8s.io

When metrics are unavailable, start with:

kubectl top pods

If that fails, check whether the API is registered:

kubectl get apiservice

Look for the metrics API service.

Then inspect Metrics Server:

kubectl get pods -n kube-system

If Metrics Server is installed in that namespace, inspect its logs:

kubectl logs \
  -n kube-system \
  deployment/metrics-server

Also check:

kubectl get --raw \
  "/apis/metrics.k8s.io/"

The exact response depends on the cluster configuration.

Common Metrics Server Problems

Kubelet Connectivity

Metrics Server must be able to communicate with Kubelets.

Network restrictions or certificate configuration can prevent metric collection.

Authentication Problems

The metrics pipeline depends on appropriate authentication and authorization between components.

API Aggregation Problems

The Resource Metrics API is exposed through Kubernetes API aggregation. Problems with the APIService configuration can make the API unavailable.

Missing Resource Requests

An HPA configured around CPU or memory utilization needs appropriate resource requests to calculate utilization correctly.

Confusing Metrics With Historical Monitoring

Resource Metrics API data is intended for autoscaling and point-in-time resource usage rather than long-term application observability.

Common Mistakes

Parsing kubectl top

Do not build production integrations around parsing human-readable CLI output.

Use the structured Kubernetes API.

Using metrics.k8s.io as a Full Monitoring System

The Resource Metrics API is not a replacement for a time-series monitoring platform.

Monitoring Only CPU

A .NET application can experience memory pressure, GC problems, database contention, or network latency while CPU remains normal.

Giving Monitoring Services Cluster-Admin Access

A read-only metrics consumer rarely needs permission to modify cluster resources.

Ignoring Resource Requests

Incorrect requests can affect scheduling and HPA behavior.

Best Practices

  1. Treat metrics.k8s.io as the Kubernetes resource-usage API.

  2. Use structured API responses rather than parsing kubectl output.

  3. Keep monitoring permissions read-only.

  4. Configure realistic CPU and memory requests.

  5. Monitor both container resources and .NET runtime metrics.

  6. Use a dedicated time-series monitoring solution for historical analysis.

  7. Monitor Metrics Server health.

  8. Test HPA behavior under realistic load.

  9. Investigate memory usage before simply increasing limits.

  10. Keep Kubernetes control-plane monitoring separate from application monitoring.

Advantages and Disadvantages

Advantages

Disadvantages

Conclusion

The metrics.k8s.io Resource Metrics API provides an important bridge between Kubernetes resource usage and automation. Kubernetes 1.37's graduation of the Resource Metrics API to stable gives teams a more mature API surface for CPU and memory metrics used by Pods, Nodes, and autoscaling workflows.

For .NET applications, the best monitoring strategy is layered:

Kubernetes Resource Metrics
          +
.NET Runtime Metrics
          +
ASP.NET Core Metrics
          +
Database Metrics

The Resource Metrics API tells you how much Kubernetes resources the workload is consuming. .NET runtime and application metrics help explain why it is consuming them.

That distinction is critical when diagnosing production issues, tuning resource requests and limits, or designing reliable autoscaling for containerized .NET applications.