PRE-REQUISITES:
1 - SUSE Observability cluster with an exposed OpenTelemetry Collector ingress endpoint.
2 - OpenTelemetry collector installed on SUSE virtualization cluster (>=1.7.x).
3 - Kube-OVN Operator (Experimental) on SUSE virtualization, Refer : https://docs.harvesterhci.io/v1.8/advanced/addons/kubeovn-operator
PROCEDURE:
Kube-OVN exposes metrics through its own services in the kube-system namespace. These need to be scraped and forwarded to SUSE Observability via the OpenTelemetry collector. For example.
http://kube-ovn-controller.kube-system.svc:10660/metrics http://kube-ovn-monitor.kube-system.svc:10661/metrics http://kube-ovn-cni.kube-system.svc:10665/metrics http://kube-ovn-pinger.kube-system.svc:8080/metrics
We need to install OpenTelemetry collector on SUSE Virtualization cluster. Deploy the OpenTelemetry Collector to Scrape Kube-OVN Metrics.
Add the Helm Repository and create Namespace.
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-chartshelm repo updatekubectl create namespace open-telemetry
The OTel collector uses bearer token authentication when sending data to SUSE Observability. To create TOKEN refer https://documentation.suse.com/cloudnative/suse-observability/latest/en/setup/otel/getting-started/getting-started-k8s-operator.html#_create_a_service_token.
Store your service token as a Kubernetes secret: Create the API Key Secret.
kubectl create secret generic suse-observability-api-key --from-literal=API_KEY=<YOUR_SERVICE_TOKEN> -n open-telemetry
Create the Helm Values File
cat << EOF > otel-kubeovn-values.yamlmode: deploymentimage: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8sreplicaCount: 1ports: metrics: enabled: trueclusterRole: create: true rules: - apiGroups: [""] resources: ["endpoints", "pods", "services", "nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["secrets"] verbs: ["get"]extraEnvs: - name: API_KEY valueFrom: secretKeyRef: name: suse-observability-api-key key: API_KEYconfig: extensions: health_check: {} bearertokenauth: scheme: SUSEObservability token: "${env:API_KEY}" receivers: prometheus: config: scrape_configs: - job_name: 'kube-ovn-controller' scrape_interval: 30s kubernetes_sd_configs: - role: endpoints namespaces: names: - kube-system selectors: - role: endpoints field: "metadata.name=kube-ovn-controller" relabel_configs: - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: metrics - source_labels: [__meta_kubernetes_pod_name] target_label: k8s_pod_name - source_labels: [__meta_kubernetes_namespace] target_label: k8s_namespace_name - source_labels: [__meta_kubernetes_endpoint_node_name] target_label: k8s_node_name - job_name: 'kube-ovn-monitor' scrape_interval: 30s kubernetes_sd_configs: - role: endpoints namespaces: names: - kube-system selectors: - role: endpoints field: "metadata.name=kube-ovn-monitor" relabel_configs: - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: metrics - source_labels: [__meta_kubernetes_pod_name] target_label: k8s_pod_name - source_labels: [__meta_kubernetes_namespace] target_label: k8s_namespace_name - source_labels: [__meta_kubernetes_endpoint_node_name] target_label: k8s_node_name - job_name: 'kube-ovn-cni' scrape_interval: 30s kubernetes_sd_configs: - role: endpoints namespaces: names: - kube-system selectors: - role: endpoints field: "metadata.name=kube-ovn-cni" relabel_configs: - source_labels: [__meta_kubernetes_endpoint_port_name] action: keep regex: metrics - source_labels: [__meta_kubernetes_pod_name] target_label: k8s_pod_name - source_labels: [__meta_kubernetes_namespace] target_label: k8s_namespace_name - source_labels: [__meta_kubernetes_endpoint_node_name] target_label: k8s_node_name - job_name: 'kube-ovn-pinger' scrape_interval: 30s kubernetes_sd_configs: - role: endpoints namespaces: names: - kube-system selectors: - role: endpoints field: "metadata.name=kube-ovn-pinger" relabel_configs: - source_labels: [__meta_kubernetes_pod_name] target_label: k8s_pod_name - source_labels: [__meta_kubernetes_namespace] target_label: k8s_namespace_name - source_labels: [__meta_kubernetes_endpoint_node_name] target_label: k8s_node_name processors: memory_limiter: check_interval: 5s limit_percentage: 80 spike_limit_percentage: 25 batch: send_batch_size: 1000 timeout: 10s resource: attributes: - key: k8s_cluster_name value: "CLUSTER_NAME" # Replcae your clustername action: upsert exporters: debug: verbosity: basic otlp/suse-observability: auth: authenticator: bearertokenauth endpoint: "otlp-stackstate.example.com:443" tls: insecure_skip_verify: true service: extensions: - health_check - bearertokenauth pipelines: metrics: receivers: - prometheus processors: - memory_limiter - batch - resource exporters: - debug - otlp/suse-observabilityEOF
Install the Otel Collector
helm upgrade --install opentelemetry-collector open-telemetry/opentelemetry-collector --values otel-kubeovn-values.yaml
Verify the logs.
kubectl -n open-telemetry logs opentelemetry-collector-58f95f7896-64hh6 -f2026-06-08T11:52:29.998Z info Metrics {"resource": {"host.name": "harvester-3", "k8s.namespace.name": "open-telemetry", "k8s.node.ip": "192.168.122.155", "k8s.node.name": "harvester-3", "k8s.pod.ip": "10.52.1.36", "k8s.pod.name": "opentelemetry-collector-58f95f7896-64hh6", "service.instance.id": "57b07a46-ec10-4ad1-a840-c719546a0aa7", "service.name": "otelcol-k8s", "service.version": "0.153.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "metrics", "resource metrics": 2, "metrics": 315, "data points": 946}2026-06-08T11:52:39.995Z info Metrics {"resource": {"host.name": "harvester-2", "k8s.namespace.name": "open-telemetry", "k8s.node.ip": "192.168.122.155", "k8s.node.name": "harvester-2", "k8s.pod.ip": "10.52.1.36", "k8s.pod.name": "opentelemetry-collector-58f95f7896-64hh6", "service.instance.id": "57b07a46-ec10-4ad1-a840-c719546a0aa7", "service.name": "otelcol-k8s", "service.version": "0.153.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "metrics", "resource metrics": 5, "metrics": 901, "data points": 1246}
Verify Metrics in SUSE Observability
Navigate to Metrics in the SUSE Observability UI and search for kube_ovn_
Successful ingestion confirms that Kube-OVN metrics are being collected and forwarded to SUSE Observability.
After the OpenTelemetry Collector has been configured and Kube-OVN metrics are successfully flowing into SUSE Observability, you can create a custom dashboard to monitor the health and performance of the Kube-OVN networking stack.
If you want to see total subnet created in kube-OVN use below query.
sum(kube_ovn_logical_switch_ports_num) by (logical_switch_name)
Some of the sample queries listed below.
Virtual Machine RX and TX Traffic per Interfacesum(delta(kube_ovn_interface_rx_bytes[5m])) by (interfaceName) sum(delta(kube_ovn_interface_tx_bytes[5m])) by (interfaceName)Logical Switch Port Countkube_ovn_logical_switch_ports_numVirtual Machine RX TX Dropped Packets (errors)sum(delta(kube_ovn_interface_rx_dropped[5m])) by (interfaceName)sum(delta(kube_ovn_interface_tx_dropped[5m])) by (interfaceName)Total Active VM Interfacescount(kube_ovn_interface_rx_packets > 0)DNS Latency(sum(delta(pinger_internal_dns_latency_ms_sum[5m])) by (nodeName))/(sum(delta(pinger_internal_dns_latency_ms_count[5m])) by (nodeName))
An example Kube-OVN dashboard:
Additional documentation about exposed metrics can be found at https://kubeovn.github.io/docs/stable/en/reference/metrics/