Collect the metrics of the specified virtual node

Updated at:
Copy as MD

When multiple virtual nodes share a single node IP address, Prometheus collects cAdvisor metrics from that IP and returns data for all virtual nodes at once—causing metric duplication. To avoid this, ACK provides a node-scoped endpoint that lets Prometheus target one virtual node by name.

How it works

ACK exposes two cAdvisor endpoints on the kubelet:

Endpoint Returns
<nodeIP>:10250/metrics/cadvisor Metrics for all virtual nodes on that IP
<nodeIP>:10250/metrics/cadvisor?nodeName=<nodeName> Metrics for pods managed by the specified virtual node only

Adding the nodeName query parameter scopes the response to a single virtual node, eliminating duplicate data when multiple virtual nodes share the same IP.

Configure Prometheus

ACK supports three Prometheus setups. Choose the one 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 the application marketplace, add the following ServiceMonitor custom resource (CR).

This configuration does two things: it 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
Important

If the cluster already uses kubelet-based service discovery to collect cAdvisor metrics, the virtual node IP is also scraped by the existing configuration, which causes duplicate data. Add the following drop rule to the existing kubelet ServiceMonitor to exclude virtual node endpoints from that job.

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 your custom configuration folder) and add the following scrape job.

The relabeling rules are divided into two groups: the first group is standard kubelet scrape configuration, and the last two rules are virtual-node-specific—they filter to virtual node endpoints only and 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
Important

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