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:
Is the Pod regularly exceeding its CPU request?
Is memory usage approaching its limit?
Are replicas balanced?
Is the application under resource pressure?
Is an HPA receiving resource metrics?
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 Layer | Example Data | Main Purpose |
|---|---|---|
| metrics.k8s.io | Pod CPU, memory | Kubernetes resource usage |
| .NET runtime metrics | GC heap, allocations | Runtime behavior |
| ASP.NET Core metrics | Requests, latency | Application behavior |
| Database metrics | Connections, query latency | Data-layer behavior |
| Full monitoring platform | Historical time series | Long-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
Treat
metrics.k8s.ioas the Kubernetes resource-usage API.Use structured API responses rather than parsing
kubectloutput.Keep monitoring permissions read-only.
Configure realistic CPU and memory requests.
Monitor both container resources and .NET runtime metrics.
Use a dedicated time-series monitoring solution for historical analysis.
Monitor Metrics Server health.
Test HPA behavior under realistic load.
Investigate memory usage before simply increasing limits.
Keep Kubernetes control-plane monitoring separate from application monitoring.
Advantages and Disadvantages
Advantages
Provides a standardized Kubernetes resource metrics API.
Supports CPU and memory monitoring for Pods and Nodes.
Integrates with Kubernetes autoscaling.
Can be consumed programmatically.
Reduces dependence on parsing CLI output.
Provides a stable API foundation for Kubernetes resource metrics.
Disadvantages
Provides only a limited set of resource metrics.
Requires Metrics Server or an equivalent implementation of the API.
Not intended for long-term historical monitoring.
Troubleshooting can involve several Kubernetes components.
Does not provide detailed .NET runtime or application-level diagnostics.
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.
Join the conversation! Your thoughts help the community grow.