Skip to content

Monitoring

Volume health in miroir is reported per node: each agent exports what its own leg of every volume sees, so a problem shows up as a metric on the node that has it (and the controller adds the few cluster-level signals the agents can't know, like RWX gateway health).

monitoring.podMonitor.enabled: true creates a Prometheus Operator PodMonitor scraping the controller and every agent on their metrics ports (the per-volume gauges are exported by the agent on each storage node; a node label is added to every series). The agent exports, per volume on that node:

Metric Meaning
miroir_volume_up_to_date 1 when this node's replica is UpToDate (unreplicated volumes are always 1 once created)
miroir_volume_connected 1 when all replication links to diskful peers are established (tie-breaker links excluded)
miroir_volume_split_brain 1 when DRBD refused to reconnect after divergence; manual resolution required
miroir_volume_suspended 1 while the snapshot write barrier freezes IO; sustained means a stranded barrier
miroir_volume_resync_ratio fraction (0-1) in sync of the least-synced diskful peer; 1 when fully in sync
miroir_volume_quorum 0 while a freeze volume has lost quorum and refuses writes, the "workloads are failing I/O" signal (always 1 under last-man-standing)
miroir_volume_disk_failed 1 when this leg's disk was detached after an I/O error and latched failed; replace the disk, then remove and re-add the replica
miroir_volume_out_of_sync_bytes worst per-peer out-of-sync bytes: the exposure if the healthiest peer is lost; also counts online-verify findings
miroir_volume_primary 1 while this node's diskful leg is Primary: the consumer pod or the RWX gateway runs here and this leg serves the I/O
miroir_volume_diskless_primary 1 while a diskless leg (client or tie-breaker) is Primary here: the consumer pays network I/O; see auto-diskful
miroir_volume_verify_last_timestamp_seconds unix time of the last completed scheduled verify; alert on staleness to catch a schedule that stopped firing
miroir_volume_verify_out_of_sync_bytes out-of-sync bytes the last scheduled verify found (0 = clean)

Each agent additionally exports its pool capacity (miroir_pool_capacity_bytes / miroir_pool_allocated_bytes / miroir_pool_meta_used_ratio), the same sample that feeds capacity-aware placement and the PoolUsageHigh condition, so pool exhaustion is alertable, not just an Event. It also exports miroir_node_drbd_kernel_info (always 1, version label): the DRBD kernel module version probed at startup, from client-only nodes too (which have no MiroirNode status). Query it for fleet version skew before a release raises the kernel floor.

For RWX volumes the controller exports miroir_export_ready: 1 while the volume's NFS gateway is serving (gateway pod available, export address published). This is the signal the per-volume gauges cannot give you: DRBD replicas stay healthy while a dead gateway leaves every NFS client hanging.

Each gateway pod additionally serves its own metrics endpoint (scraped by a second PodMonitor, with node and volume labels): miroir_gateway_nfs_healthy is the result of the last liveness probe's NFS NULL call against the pod's local ganesha. The same probe backs the pod's /healthz, so a ganesha that still accepts TCP connections but has stopped answering NFS fails liveness and is restarted — previously that failure mode was invisible.

Prometheus is not the only surface. Volume health also flows through the CSI VolumeCondition: enable sidecars.healthMonitor.enabled and split-brain, failed-disk, and degraded volumes surface as events on their PVCs (kubectl describe pvc).

Starter alerts and dashboard

monitoring.prometheusRule.enabled: true ships starter alerts for all of the above (split-brain, quorum lost, stranded barrier, disk failed, degraded replication, sustained out-of-sync, an unavailable RWX export, a stale verify schedule, pool and thin-metadata usage, and a down agent — a node whose agent stops answering scrapes loses every miroir_* series, so none of the per-volume alerts can fire for it; the kernel-floor refusal to start looks exactly like this), and monitoring.dashboards.enabled: true installs a Grafana dashboard, either a sidecar-labelled ConfigMap or a grafana-operator GrafanaDashboard CR via monitoring.dashboards.grafanaOperator.