Since not all production setups use a flat network, the prometheus openstack service discovery generates one target per network interface (see documentation).

The instance role discovers one target per network interface of Nova instance. The target address defaults to the private IP address of the network interface.

This has the side effect that exporters on instances with multiple network interfaces are being scraped multiple times. One solution to this problem is to set the network name of the network interface from which to scrape the metrics as metadata on the instance (i.e. prometheus_node_exporter_network) and compare the value against the __meta_openstack_address_pool label. A possible configuration could look as follows:

- job_name: "node_exporter"
  openstack_sd_configs:
  - ...
  relabel_configs:
  - source_labels: [__meta_openstack_instance_status]
    action: keep
    regex: "ACTIVE"

  - source_labels: [__meta_openstack_tag_prometheus_node_exporter_scrape]
    action: keep
    regex: "true"

  - source_labels: [__meta_openstack_tag_prometheus_node_exporter_network,__meta_openstack_address_pool]
    separator: ""
    regex: ((networkA){2}|(networkB){2})
    action: keep

  - source_labels: [__address__, __meta_openstack_tag_prometheus_node_exporter_port]
    action: replace
    regex: ([^:]+)(?::\d+)?;(\d+)
    replacement: $1:$2
    target_label: __address__

  - source_labels: [__meta_openstack_instance_name]
    target_label: instance

Note. Each network needs to be added to the address pool relabel_config regex. As a more general approach using backreferences like (\w+);\1 won’t work as prometheus uses RE2 as regex engine which doesn’t support backreferences.