Kubernetes (Grafana Agent) and VM / Bare-Metal (Prometheus)
Prometheus can collect far more data than is operationally useful. Without deliberate control, storage fills faster than expected, queries slow down, and effective retention falls below the configured target. The goal of filtering and relabeling is to keep:
This is how K2view keeps the monitoring system sustainable as environments grow. The principles are the same for both Kubernetes and VM / bare-metal deployments. The syntax for applying them differs between Grafana Agent (Kubernetes) and Prometheus YAML (VM).
This how-to covers:
It does not define a fixed allowlist. The exact rules should reflect the environment and the operational questions you need to answer.
[ K8s + VM ] Applies to both deployment models.
The standard K2view model is:
This keeps the Fabric-side exporter configuration simple and stable. Observability policy is centralized in the collection layer, where storage and retention effects are directly visible and can be adjusted without restarting Fabric or rebuilding the container image.
[ K8s + VM ] Applies to both deployment models.
Without filtering and relabeling, the collection layer can ingest:
The result is faster storage consumption, slower queries, and a Prometheus instance where configured retention is never fully achieved because storage fills sooner than the time window.
The real scaling pressure in Prometheus is not the number of metric names — it is the number of active series. A single metric with multiple labels can expand into hundreds or thousands of distinct series depending on the number of unique label value combinations.
For example, a metric with labels for namespace, pod, container, and device, each with many possible values, can generate far more series than its single metric name suggests.
Always monitor active series as your primary Prometheus health signal:
prometheus_tsdb_head_series
Note: A change that keeps metric names the same but reduces label cardinality can significantly reduce active series. A change that drops metric names but keeps high-cardinality labels may have less impact than expected. Focus on series count, not name count.
Prometheus retention has two limits: a time window and a storage size cap. Whichever is reached first determines effective retention. If storage fills before the time window expires, Prometheus starts dropping older data early.
Filtering directly extends effective retention. Fewer active series means slower storage growth, which means the time-based retention target is more likely to be met in practice.
[ K8s + VM ] Applies to both deployment models.
Filtering decides which metric families to keep and which to drop entirely.
Use filtering when:
Ask these questions about each metric family:
If the answer to all four is no, drop the family.
Relabeling decides which labels to keep, normalize, or drop on metrics that are worth retaining.
Use relabeling when:
Ask these questions about each label on a high-volume metric:
Labels that encode ephemeral or overly detailed dimensions — such as individual pod names, request IDs, or content-addressed hashes — are typical candidates for removal.
Note: The distinction matters: sometimes the right answer is to drop the metric; sometimes the right answer is to keep the metric but reduce its labels. Evaluate each case separately.
[ K8s ] In Kubernetes, filtering and relabeling are configured in the Grafana Agent River pipeline using prometheus.relabel components.
The prometheus.relabel component sits between the scrape and the remote_write destination. It applies rules to the scraped metrics before they are forwarded.
A complete example showing filtering to a curated set of Fabric and JVM families, plus a label drop:
prometheus.relabel "fabric_filter" {
// Keep only the metric families we care about
rule {
source_labels = ["__name__"]
regex = "fabric_.*|jvm_.*|tomcat_.*|process_.*"
action = "keep"
}
// Drop a high-cardinality label not needed for dashboards
rule {
action = "labeldrop"
regex = "some_volatile_label"
}
forward_to = [prometheus.relabel.metrics_service.receiver]
}
Wire the scrape component to forward to this relabel component:
prometheus.scrape "fabric_jmx" {
targets = discovery.relabel.fabric_pods.output
job_name = "fabric-jmx"
forward_to = [prometheus.relabel.fabric_filter.receiver]
}
[ VM / Bare-Metal ] In VM deployments, filtering and relabeling are configured using metric_relabel_configs inside each scrape job in prometheus.yml.
metric_relabel_configs runs after the scrape and controls what gets written to the Prometheus time-series database. A complete example:
- job_name: fabric-jmx
metrics_path: /metrics
static_configs:
- targets:
- <FABRIC_HOST>:7170
metric_relabel_configs:
# Keep only the metric families we care about
- source_labels: [__name__]
regex: 'fabric_.*|jvm_.*|tomcat_.*|process_.*'
action: keep
# Drop a high-cardinality label not needed for dashboards
- action: labeldrop
regex: 'some_volatile_label'
Note: metric_relabel_configs controls what is stored. relabel_configs (without the metric_ prefix) controls target selection before the scrape. Use metric_relabel_configs for metric family filtering and label management.
[ K8s + VM ] Node Exporter is the most common source of excessive metric volume. It exposes many metric families by default, most of which have little operational value in typical deployments.
Node Exporter exposes dozens of metric families covering every aspect of the operating system. A practical starting point is to keep only the families directly useful for infrastructure monitoring:
Families that are rarely needed and worth dropping first:
[ K8s ] kube-state-metrics is a Kubernetes-only component. It does not exist in VM / bare-metal deployments.
kube-state-metrics exposes Kubernetes object state metrics. The volume depends on the number of namespaces, deployments, pods, and other objects in the cluster. In large clusters it can generate significant series counts.
Focus on retaining the families that support workload health monitoring:
Consider dropping or limiting:
[ K8s + VM ] The Fabric exporter exposes broadly by default. Most environments only need a curated subset.
The core families worth retaining for operational monitoring:
Review your dashboards and alerts to determine which specific metric names within these families are actually used, and consider tightening the regex further.
[ K8s + VM ] Applies to both deployment models.
Before making changes, record the current active series count. This is your baseline for measuring improvement:
prometheus_tsdb_head_series
Also note which jobs are contributing the most series. A per-job breakdown is available via:
sum by (job) (scrape_series_added)
Start with the exporters that contribute the most series. Node Exporter and kube-state-metrics (K8s only) are almost always the largest contributors in unfiltered environments. Fabric metrics are typically more manageable but should still be reviewed.
Apply a keep rule that retains only the families you have identified as operationally useful. Start conservatively — it is easier to add back a metric family later than to discover a missing dashboard panel after dropping it.
After applying the rule, reload or redeploy the collection layer configuration and monitor active series.
For metrics that are useful but generating too many series, review the label set. Drop labels that are not used in any dashboard filter, alert condition, or aggregation.
Check the active series count again after applying labeldrop rules.
After filtering changes, confirm that active series has decreased and that storage growth rate has improved. Also confirm that configured dashboards and alerts still function correctly — check each panel and alert condition individually.
After stabilizing active series, review whether the configured retention target is now realistically achievable given current storage. Adjust the storage size cap or retention window if needed to match the new, lower ingestion rate.
[ K8s + VM ] Applies to both deployment models.
Both deployment models:
Kubernetes only:
VM / Bare-Metal only:
Kubernetes (Grafana Agent) and VM / Bare-Metal (Prometheus)
Prometheus can collect far more data than is operationally useful. Without deliberate control, storage fills faster than expected, queries slow down, and effective retention falls below the configured target. The goal of filtering and relabeling is to keep:
This is how K2view keeps the monitoring system sustainable as environments grow. The principles are the same for both Kubernetes and VM / bare-metal deployments. The syntax for applying them differs between Grafana Agent (Kubernetes) and Prometheus YAML (VM).
This how-to covers:
It does not define a fixed allowlist. The exact rules should reflect the environment and the operational questions you need to answer.
[ K8s + VM ] Applies to both deployment models.
The standard K2view model is:
This keeps the Fabric-side exporter configuration simple and stable. Observability policy is centralized in the collection layer, where storage and retention effects are directly visible and can be adjusted without restarting Fabric or rebuilding the container image.
[ K8s + VM ] Applies to both deployment models.
Without filtering and relabeling, the collection layer can ingest:
The result is faster storage consumption, slower queries, and a Prometheus instance where configured retention is never fully achieved because storage fills sooner than the time window.
The real scaling pressure in Prometheus is not the number of metric names — it is the number of active series. A single metric with multiple labels can expand into hundreds or thousands of distinct series depending on the number of unique label value combinations.
For example, a metric with labels for namespace, pod, container, and device, each with many possible values, can generate far more series than its single metric name suggests.
Always monitor active series as your primary Prometheus health signal:
prometheus_tsdb_head_series
Note: A change that keeps metric names the same but reduces label cardinality can significantly reduce active series. A change that drops metric names but keeps high-cardinality labels may have less impact than expected. Focus on series count, not name count.
Prometheus retention has two limits: a time window and a storage size cap. Whichever is reached first determines effective retention. If storage fills before the time window expires, Prometheus starts dropping older data early.
Filtering directly extends effective retention. Fewer active series means slower storage growth, which means the time-based retention target is more likely to be met in practice.
[ K8s + VM ] Applies to both deployment models.
Filtering decides which metric families to keep and which to drop entirely.
Use filtering when:
Ask these questions about each metric family:
If the answer to all four is no, drop the family.
Relabeling decides which labels to keep, normalize, or drop on metrics that are worth retaining.
Use relabeling when:
Ask these questions about each label on a high-volume metric:
Labels that encode ephemeral or overly detailed dimensions — such as individual pod names, request IDs, or content-addressed hashes — are typical candidates for removal.
Note: The distinction matters: sometimes the right answer is to drop the metric; sometimes the right answer is to keep the metric but reduce its labels. Evaluate each case separately.
[ K8s ] In Kubernetes, filtering and relabeling are configured in the Grafana Agent River pipeline using prometheus.relabel components.
The prometheus.relabel component sits between the scrape and the remote_write destination. It applies rules to the scraped metrics before they are forwarded.
A complete example showing filtering to a curated set of Fabric and JVM families, plus a label drop:
prometheus.relabel "fabric_filter" {
// Keep only the metric families we care about
rule {
source_labels = ["__name__"]
regex = "fabric_.*|jvm_.*|tomcat_.*|process_.*"
action = "keep"
}
// Drop a high-cardinality label not needed for dashboards
rule {
action = "labeldrop"
regex = "some_volatile_label"
}
forward_to = [prometheus.relabel.metrics_service.receiver]
}
Wire the scrape component to forward to this relabel component:
prometheus.scrape "fabric_jmx" {
targets = discovery.relabel.fabric_pods.output
job_name = "fabric-jmx"
forward_to = [prometheus.relabel.fabric_filter.receiver]
}
[ VM / Bare-Metal ] In VM deployments, filtering and relabeling are configured using metric_relabel_configs inside each scrape job in prometheus.yml.
metric_relabel_configs runs after the scrape and controls what gets written to the Prometheus time-series database. A complete example:
- job_name: fabric-jmx
metrics_path: /metrics
static_configs:
- targets:
- <FABRIC_HOST>:7170
metric_relabel_configs:
# Keep only the metric families we care about
- source_labels: [__name__]
regex: 'fabric_.*|jvm_.*|tomcat_.*|process_.*'
action: keep
# Drop a high-cardinality label not needed for dashboards
- action: labeldrop
regex: 'some_volatile_label'
Note: metric_relabel_configs controls what is stored. relabel_configs (without the metric_ prefix) controls target selection before the scrape. Use metric_relabel_configs for metric family filtering and label management.
[ K8s + VM ] Node Exporter is the most common source of excessive metric volume. It exposes many metric families by default, most of which have little operational value in typical deployments.
Node Exporter exposes dozens of metric families covering every aspect of the operating system. A practical starting point is to keep only the families directly useful for infrastructure monitoring:
Families that are rarely needed and worth dropping first:
[ K8s ] kube-state-metrics is a Kubernetes-only component. It does not exist in VM / bare-metal deployments.
kube-state-metrics exposes Kubernetes object state metrics. The volume depends on the number of namespaces, deployments, pods, and other objects in the cluster. In large clusters it can generate significant series counts.
Focus on retaining the families that support workload health monitoring:
Consider dropping or limiting:
[ K8s + VM ] The Fabric exporter exposes broadly by default. Most environments only need a curated subset.
The core families worth retaining for operational monitoring:
Review your dashboards and alerts to determine which specific metric names within these families are actually used, and consider tightening the regex further.
[ K8s + VM ] Applies to both deployment models.
Before making changes, record the current active series count. This is your baseline for measuring improvement:
prometheus_tsdb_head_series
Also note which jobs are contributing the most series. A per-job breakdown is available via:
sum by (job) (scrape_series_added)
Start with the exporters that contribute the most series. Node Exporter and kube-state-metrics (K8s only) are almost always the largest contributors in unfiltered environments. Fabric metrics are typically more manageable but should still be reviewed.
Apply a keep rule that retains only the families you have identified as operationally useful. Start conservatively — it is easier to add back a metric family later than to discover a missing dashboard panel after dropping it.
After applying the rule, reload or redeploy the collection layer configuration and monitor active series.
For metrics that are useful but generating too many series, review the label set. Drop labels that are not used in any dashboard filter, alert condition, or aggregation.
Check the active series count again after applying labeldrop rules.
After filtering changes, confirm that active series has decreased and that storage growth rate has improved. Also confirm that configured dashboards and alerts still function correctly — check each panel and alert condition individually.
After stabilizing active series, review whether the configured retention target is now realistically achievable given current storage. Adjust the storage size cap or retention window if needed to match the new, lower ingestion rate.
[ K8s + VM ] Applies to both deployment models.
Both deployment models:
Kubernetes only:
VM / Bare-Metal only: