When multiple virtual nodes share the same node IP address, Prometheus scrapes cAdvisor metrics from that IP through the kubelet Service. Each scrape returns data for all virtual nodes, causing metric duplication. To avoid this, ACK provides a node-scoped endpoint that lets Prometheus target one virtual node by name.
Prerequisites
Before you begin, ensure that you have:
-
The ACK Virtual Node add-on installed, version v2.11.0 or later. For more information, see ACK Virtual Node.
How it works
ACK retains the original cAdvisor endpoint on the kubelet and adds a second node-scoped endpoint:
| Endpoint | Returns |
|---|---|
<nodeIP>:10250/metrics/cadvisor |
Metrics for all virtual nodes on that IP |
<nodeIP>:10250/metrics/cadvisor?nodeName=<nodeName> |
Metrics only for pods managed by the specified virtual node |
Adding the nodeName query parameter scopes the response to a single virtual node.
Configure Prometheus
ACK supports three Prometheus setups: Alibaba Cloud Managed Service for Prometheus, the community edition Prometheus Operator, and open-source Prometheus. Select the tab that matches your deployment.
Alibaba Cloud Managed Service for Prometheus
No configuration changes are required. The node-scoped endpoint is supported by default.
Community edition Prometheus Operator
If you use the community edition Prometheus Operator with ack-prometheus-operator from App Marketplace, add the following ServiceMonitor custom resource (CR).
This configuration keeps only endpoints whose target name starts with virtual-kubelet, and adds nodeName as a query parameter so each virtual node is scraped individually.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: virtual-kubelet
namespace: monitoring
labels:
k8s-app: kubelet
# Required label for automatic management by Prometheus Operator.
release: prometheus-operator
spec:
jobLabel: k8s-app
selector:
matchLabels:
k8s-app: kubelet
namespaceSelector:
matchNames:
- kube-system
endpoints:
- port: https-metrics
interval: 15s
scheme: https
path: /metrics/cadvisor
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
tlsConfig:
caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecureSkipVerify: true
relabelings:
# Keep only virtual node endpoints (names starting with "virtual-kubelet").
- sourceLabels: [__meta_kubernetes_endpoint_address_target_name]
regex: (^virtual-kubelet.*)
action: keep
# Set the nodeName query parameter to the virtual node's name.
- sourceLabels: [__meta_kubernetes_endpoint_address_target_name]
regex: (^virtual-kubelet.*)
targetLabel: __param_nodeName
replacement: ${1}
action: replace
If the cluster already uses kubelet-based service discovery to collect cAdvisor metrics, add the following drop rule to the existing kubelet ServiceMonitor. This removes the scrape configuration for <virtual node IP>:10250/metrics/cadvisor and prevents duplicate data.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
...
spec:
endpoints:
- path: /metrics/cadvisor
port: https-metrics
...
relabelings:
# Drop endpoints whose target name starts with "virtual-kubelet".
# This prevents duplicate collection from <virtual node IP>:10250/metrics/cadvisor.
- action: drop
regex: (^virtual-kubelet.*)
sourceLabels:
- __meta_kubernetes_endpoint_address_target_name
Open-source Prometheus
Locate your Prometheus configuration file (typically /etc/prometheus/prometheus.yml or under your custom configuration directory) and add the following scrape job.
The relabeling rules fall into two groups. The first group is the standard kubelet scrape configuration. The last two rules are virtual-node-specific and keep only virtual node endpoints. They also inject the nodeName query parameter.
scrape_configs:
# ... other job configurations ...
- job_name: monitoring/virtual-kubelet/0
honor_timestamps: true
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /metrics/cadvisor
scheme: https
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
relabel_configs:
# --- Standard kubelet service discovery rules ---
- source_labels: [__meta_kubernetes_service_label_k8s_app]
separator: ;
regex: kubelet
replacement: $1
action: keep
- source_labels: [__meta_kubernetes_endpoint_port_name]
separator: ;
regex: https-metrics
replacement: $1
action: keep
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
regex: Node;(.*)
target_label: node
replacement: ${1}
action: replace
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
regex: Pod;(.*)
target_label: pod
replacement: ${1}
action: replace
- source_labels: [__meta_kubernetes_namespace]
separator: ;
regex: (.*)
target_label: namespace
replacement: $1
action: replace
- source_labels: [__meta_kubernetes_service_name]
separator: ;
regex: (.*)
target_label: service
replacement: $1
action: replace
- source_labels: [__meta_kubernetes_pod_name]
separator: ;
regex: (.*)
target_label: pod
replacement: $1
action: replace
- source_labels: [__meta_kubernetes_pod_container_name]
separator: ;
regex: (.*)
target_label: container
replacement: $1
action: replace
- source_labels: [__meta_kubernetes_service_name]
separator: ;
regex: (.*)
target_label: job
replacement: ${1}
action: replace
- source_labels: [__meta_kubernetes_service_label_k8s_app]
separator: ;
regex: (.+)
target_label: job
replacement: ${1}
action: replace
- separator: ;
regex: (.*)
target_label: endpoint
replacement: https-metrics
action: replace
# --- Virtual-node-specific rules ---
# Keep only endpoints whose target name starts with "virtual-kubelet".
- source_labels: [__meta_kubernetes_endpoint_address_target_name]
separator: ;
regex: (^virtual-kubelet.*)
replacement: $1
action: keep
# Set the nodeName query parameter to the virtual node's name.
- source_labels: [__meta_kubernetes_endpoint_address_target_name]
separator: ;
regex: (^virtual-kubelet.*)
target_label: __param_nodeName
replacement: ${1}
action: replace
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- kube-system
If the cluster already uses kubelet-based service discovery to collect cAdvisor metrics, add the following drop rule to the existing scrape job (job name: monitoring/ack-prometheus-operator-kubelet/0). This prevents Prometheus from also scraping <virtual node IP>:10250/metrics/cadvisor and producing duplicate metrics.
scrape_configs:
# ... other job configurations ...
- job_name: monitoring/ack-prometheus-operator-kubelet/0
honor_labels: true
honor_timestamps: true
...
relabel_configs:
...
# Drop virtual node endpoints to prevent duplicate collection of /metrics/cadvisor.
- source_labels: [__meta_kubernetes_endpoint_address_target_name]
separator: ;
regex: (^virtual-kubelet.*)
replacement: $1
action: drop