Cluster Guide
1 How the Cluster Works
ovios-cluster builds an active/passive cluster on ZFS. One node is the
primary: it serves your data and holds the floating virtual IP (VIP). The
other nodes are replicas, which follow the primary and hold a mirror of its data. A replica
can sit in the same rack or at your disaster-recovery site.
- Replication is asynchronous, using
zfs send -w | zfs recv, every 10 seconds by default. - Liveness is tracked with heartbeats over mutually authenticated TLS.
- Witnesses are optional vote-only nodes. They hold no data, are never promoted and need no fencing, but they let the cluster tell a dead node from a network partition.
- Failover moves the primary role, and the VIP, to a replica. It is manual by default and free. Automatic failover is a licensed feature.
HA and replication are separate tools. ovios-cluster mirrors a primary to
secondaries and fails over. retadm replicates individual
volumes and LUNs for backup, and works independently of a cluster.
What is free and what is licensed
| Feature | Free | Licensed |
|---|---|---|
| Replication, retention, resume, status, metrics | Yes | |
| Fencing, quorum, epoch checks, receive guard, self-demotion | Yes | |
| Any number of nodes, witnesses, tiebreaker | Yes | |
Planned maintenance with switchover (ovios-cluster switchover):
a loss-free hand-over to a replica |
Yes | |
Manual failover (ovios-cluster promote) |
Yes | |
| Automatic failover | Subscription |
A license unlocks the feature, not nodes, so adding or replacing nodes never needs a new license. Nothing that protects your data consults the license: it only decides whether a replica may promote itself automatically.
2 How It Keeps Data Safe
Failover is only useful if it never makes things worse. These are the protections built into the cluster.
| Risk | Protection |
|---|---|
| Two primaries (split brain) | Every promotion raises a cluster epoch, saved before anything is exposed. The higher epoch always wins, so a returning old primary demotes itself instead of serving. |
| Old primary keeps writing | Promotion fences it first (for example an IPMI power-off). A primary that loses
quorum for lease_seconds also steps down by itself, and replicas wait longer than that
before promoting. |
| A cut-off replica promotes wrongly | It needs a strict majority of votes, and no reachable voter may still see the primary. |
| Replica too far behind | Promotion is refused if the newest replicated snapshot is older than
max_replica_lag_seconds. |
| Old primary overwrites the new one | The receiving node refuses streams from a sender with an older epoch, an unknown sender, or for an excluded dataset. |
| Destructive "self-healing" | A failed transfer is retried and resumed, but never destroys snapshots or forces a receive.
Divergence is reported as DIVERGED and fixed only by an explicit
resync. |
| Spoofed peers | Heartbeats use mutual TLS with a per-cluster CA, and SSH host keys are pinned. A changed host key is a hard error. |
Rehearse before you rely on it. Build a staging pair first and test a failover, including pulling the primary's power, before using the cluster for production data.
3 Prerequisites
| Requirement | Details |
|---|---|
| Two or more OviOS nodes | At least a primary and a replica, on IPv4 addresses and able to reach each other. |
| A free VIP | An unused address on the same network as the nodes, optional but normally what clients connect to. |
| Root SSH key access | The primary must reach every node as root without a password. See Passwordless SSH in the Replication Guide. The first contact pins the node's host key. |
| ZFS pools with the same names | Each replica needs the destination pool for every replicated dataset. Replication fails with destination pool does not exist otherwise. Witnesses need no pools. |
| ovios-cluster on every node | Installed at /usr/bin/ovios-cluster. add checks this, because the
receiving side runs it over SSH as a guard. |
| For automatic failover | A quorum of three or more voters (a witness node, or a tiebreaker IP), a
fence_cmd on every data node, and a license. |
Two nodes cannot tell a dead peer from a partition. Add a witness
(add --witness) or set a --tiebreaker IP such as your default gateway. Without
one, automatic failover is rejected by validation, and a lone primary keeps serving when its peer dies.
On a stateless (live) node the cluster configuration is part of the node configuration saved to your pools, so it comes back at every boot. See the Live-OS guide.
4 Step 1 — Create the Cluster
All commands in this guide are run in the ovios-shell, where oc is a shorthand for
ovios-cluster. On the node that should start as primary, run ovios-cluster init. It creates the cluster CA, a
node identity and the configuration, and makes this node the primary.
ovios-shell ➤ ovios-cluster init --vip 10.0.0.100 --tiebreaker 10.0.0.254
Cluster initialized. Node 5d1f0c3a-... (10.0.0.1) is primary at epoch 1.
Cluster ID: <id> (needed to request a license for automatic failover)
Next: start the cluster daemon with 'options cluster.enable on' (or 'service ovios-cluster enable') in ovios-shell,
then 'ovios-cluster add <ip>' for each other node.
Then start the cluster daemon with the cluster.enable option, or the equivalent
service command, and check that it is running:
ovios-shell ➤ options cluster.enable on
option cluster.enable on
ovios-shell ➤ service ovios-cluster status
service ovios-cluster enable does the same as options cluster.enable on: it
starts the daemon and keeps it enabled, including across stateless reboots. The flag is saved in the node
configuration, so config sync carries it to the other nodes.
| Option | Meaning |
|---|---|
--vip |
The floating IP that follows the primary. Optional. |
--interface |
Interface for the VIP. Default: the default-route interface. |
--tiebreaker |
An IP (for example the gateway) that counts as an extra vote, so a two-node cluster can tell a partition from a dead peer. |
--hbport |
Heartbeat port. Default 9064. |
--force |
Overwrite an existing configuration, creating a new CA and identity. |
Note the Cluster ID. A license is bound to it, not to hardware.
5 Step 2 — Add Nodes
Run ovios-cluster add on the primary for every other node. It pins the node's SSH host key,
checks that the address really belongs to that host, checks that ovios-cluster (and, for data nodes, ZFS) is
installed, issues the node a certificate and starts its daemon.
# a data node (replica)
ovios-shell ➤ ovios-cluster add 10.0.0.2
Node 5d1f0c3a-... (10.0.0.2) added as replica.
# a witness: votes only, no data, never promoted
ovios-shell ➤ ovios-cluster add --witness 10.0.0.3
Cloned machines. If a node was cloned from another, add refuses a duplicate
node ID. Remove /etc/ovios-cluster/node-id on the new machine and try again.
6 Step 3 — Configure and Sync
The configuration lives in /etc/ovios-cluster/ovios-cluster.yaml. Edit it on the
primary only, then run ovios-cluster sync. Sync validates the file and pushes
it to every node, and running daemons pick the change up automatically. An invalid file is rejected and the
previous configuration stays in force.
The settings you will most often change:
# services started (in order) on promotion, stopped (in reverse) on demotion
services:
- ovios-nfs.service
- ovios-smb.service
- ovios-iscsi.service
# every data node that may be fenced needs a command that really powers it off
nodes:
- id: 5d1f0c3a-...
ip: 10.0.0.1
fence_cmd: ipmitool -I lanplus -H 10.0.1.1 -U admin -P secret chassis power off
- id: 5d1f0c3a-...
ip: 10.0.0.2
fence_cmd: ipmitool -I lanplus -H 10.0.1.2 -U admin -P secret chassis power off
ovios-shell ➤ ovios-cluster sync
Editing the configuration safely
On the primary, service ovios-cluster edit opens the file in $VISUAL /
$EDITOR (nano or vi if unset) on a private copy. When you close the editor the copy is checked
with ovios-cluster sync --check --file; an invalid file is never saved and you
can edit again or discard. A valid file replaces the live one (the old one is kept as
ovios-cluster.yaml.bak) and you are asked whether to push it to the other nodes. If the live
file changed while you were editing, it is not overwritten and your edit is kept in a temporary file.
ovios-shell ➤ service ovios-cluster edit
The check rejects bad YAML, misspelt (unknown) keys, inconsistent settings and automatic failover without a license. You can run it yourself on any file without pushing anything:
ovios-shell ➤ ovios-cluster sync --check --file /root/new.yaml
The edit command needs an ovios-cluster that supports sync --check. With an older
binary it says so and saves nothing.
Configuration is synced automatically — including passwords
ovios-cluster sync above only pushes the cluster configuration file. The
OviOS configuration (LUNs, volumes, shares, iSCSI targets, users and options) is a separate
sync, and it keeps the replicas ready to take over:
1. It runs by itself, and can also be run by hand. The configuration is synced from the
primary to the replicas automatically after every change you make on the primary: creating,
mapping or unmapping a LUN, creating a volume, adding a share, and so on. You can also trigger it manually
at any time, on the primary:
sync-config cluster-sync.
2. Passwords are synced too. The passwords of root, ovios and every other local user, and the passwords of the SMB users, are copied from the primary to the replica(s) along with the configuration. Change passwords on the primary, so that the replicas, and the node that takes over after a failover, accept the same logins. Network settings and the ZFS host ID are never synced: each node keeps its own.
3. The same applies to retadm. With autosync.enable turned on, the
configuration, including the passwords of local and SMB users, is also synced to your
replication partners.
The cluster itself replicates data and dataset properties: sharesmb,
sharenfs, mountpoint, quota and the LUN properties (type, mapping, id,
target group, provisioning). ovios-cluster push-archive <file.tar.gz> distributes a
configuration archive from the primary to every other data node.
Datasets of the operating system (rpool, bpool and their children) are excluded
from replication by default. Add more under datasets.exclude if some data should not be
mirrored.
7 Step 4 — Check Status
ovios-cluster status shows the whole cluster from any node (add --json for scripts).
ovios-shell ➤ ovios-cluster status
Cluster: ovios-cluster
This node: e303ee93-c225-4e42-9e3d-068dfeecd858 (PRIMARY, applied: primary)
Primary: e303ee93-c225-4e42-9e3d-068dfeecd858 epoch 21
Votes: 3/3 quorum
Failover: automatic=true (licensed)
License: expiring - license expires on 2026-11-12 (28 day(s) left): renew to keep automatic failover
Cluster ID: bcd94e2b-a6f6-432b-948d-77455f04fab7
VIP: 10.0.0.160 present locally=true
Last: none: primary with valid lease
PEER IP TYPE ALIVE LAST EPOCH PRIMARY
3997fac1-40fa-4981-ad03-da5b7e18d981 10.0.0.25 data true 0s ago 21 e303ee93-c225-4e42-9e3d-068dfeecd858
00c81f6a-30f5-4121-b54f-23d8469928a7 10.0.0.98 witness true 0s ago 21 e303ee93-c225-4e42-9e3d-068dfeecd858
REPLICATION DATASET LAG STATE
3997fac1-40fa-4981-ad03-da5b7e18d981 data/lun01 14s ok
3997fac1-40fa-4981-ad03-da5b7e18d981 data/lun02 1s ok
3997fac1-40fa-4981-ad03-da5b7e18d981 data/lun03 14s ok
3997fac1-40fa-4981-ad03-da5b7e18d981 data/vol01 14s ok
3997fac1-40fa-4981-ad03-da5b7e18d981 data/vol02 13s ok
This is a three-node cluster: the primary (this node), a data node holding the replicas, and a witness that only votes.
| Replication state | Meaning |
|---|---|
ok |
Replicating normally. LAG is the age of the newest replicated snapshot. |
error: … |
A transfer failed. It is retried automatically and resumed from a token. |
DIVERGED |
The replica holds changes the primary does not have. Needs an explicit resync. |
FENCED |
The receiving node refused the stream (older epoch, unknown sender or excluded dataset). |
PROPERTIES NOT SYNCED |
Data is fine but a property could not be applied (for example a quota below current usage). The next cycle retries. |
Cluster Stats page and prompt marker
On the primary only, the web dashboard shows a Cluster Stats button. It opens a page with the cluster status, votes, VIP and failover state, every node with its heartbeat age, the replication state of each dataset (lag, diverged, errors) and the last lines of the cluster log. It refreshes by itself, and on a replica or a node outside a cluster the page does not exist.
In the shell, the prompt shows the node's role — [PRIMARY] in red or [replica] in
green — so you do not run a command on the wrong node. See shell.prompt in the
Options Guide.
Metrics for Prometheus are available when metrics_listen is set: epoch, role, quorum votes,
peer state, and per-dataset lag, divergence and errors.
8 Planned Maintenance (Switchover)
To do maintenance on the current primary, hand the primary role to a replica first with
ovios-cluster switchover. It is loss-free: the primary stops serving, sends the
replica its final state, and the replica takes over the VIP and the services. Nothing is fenced or powered
off, and no write is lost. Switchover is free and needs no license.
# 1. rehearse: runs every check and the pre-sync, but does not hand over
ovios-shell ➤ ovios-cluster switchover --check
# 2. do it (it asks for confirmation; -y skips it)
ovios-shell ➤ ovios-cluster switchover
# or choose the replica yourself (node ID or IP)
ovios-shell ➤ ovios-cluster switchover --host 10.0.0.2
Without --host, the cluster picks the healthiest replica: the one with the smallest replication
lag, with the configuration order breaking ties.
What it checks first
The replica must be reachable, agree on who the primary is, replicate cleanly (no divergence, no errors, within
max_replica_lag_seconds), and confirm over SSH that it can take over.
What it does
-
Waits for replication. It blocks the next replication cycle and never interrupts a transfer in flight. Every ten seconds it says what is sending, what is queued and what replication is doing right now.
-
Pre-sync while this node still serves, so that most data is already on the replica, and a replica that cannot receive is found before anything is stopped. If it fails, nothing has changed.
-
Stops serving: services, VIP and datasets (read-only), step by step. This is the point of no return.
-
Final sync of the now-final state to the replicas. It is short, thanks to the pre-sync.
-
Hand-over. The replica takes over at the next epoch once it holds the final snapshot, and its own steps are shown while the old primary waits.
Clients are disconnected from step 3 on, typically for seconds up to a minute. iSCSI initiators reconnect to the virtual IP on the new primary.
If something goes wrong, or you interrupt it
- If anything fails before the replica has taken over, the old primary resumes as primary.
- If it cannot be known whether the replica promoted (no answer, no heartbeat), the old primary
stays down on purpose and says so.
ovios-cluster promoteon it resumes it. - Ctrl-C during steps 1 and 2 gives up: nothing is changed and replication continues. If your
terminal swallows Ctrl-C (the OviOS shell does), run
ovios-cluster switchover --abortfrom another session. - From the line "Point of no return" on, Ctrl-C is ignored. Stopping halfway could leave the
cluster without a primary, so the switchover runs to the end, or undoes itself if something fails,
even if the command is closed or the SSH session drops. Follow it with
ovios-cluster status: theLast:line shows the step in progress.
When the maintenance is done, you can switch back the same way, from the new primary.
9 Manual Failover
Manual failover is free and needs no license. Run ovios-cluster promote on the replica that
should take over.
ovios-shell ➤ ovios-cluster promote
Promotion runs as a sequence with rollback: safety checks, the pre_promote hook, fencing of the
old primary, saving the new epoch, then mounting datasets, bringing up the VIP (with an ARP announcement),
starting the configured services and running the post_promote hook. If a step fails, the local
steps are undone and the epoch is never reused.
Without --force, promotion is refused while:
- the primary is still reachable,
- there is no quorum,
- another node still sees the primary, or
- the replicated data is older than
max_replica_lag_seconds.
--force skips those checks and continues even if fencing fails. Use it only
after you have confirmed that the old primary is really down.
Planned maintenance? Do not use promote on a healthy cluster. Use
ovios-cluster switchover, which hands the role over without losing a
write.
10 Manual Demotion
Normally the cluster demotes a node by itself. If it did not — for example a former primary that came back
with writable datasets or the VIP still up — run ovios-cluster demote on that node. It stops
replication and the configured services, removes the VIP, and unmounts the datasets and sets them readonly.
ovios-shell ➤ ovios-cluster demote
If the cluster still names this node as primary, demote refuses unless you add
--force, because the cluster is then left without a serving primary. The node
stays down until another node is promoted or promote is run on it again. Restarting the
daemon also ends a forced demotion of the primary. Normally, promote another node first.
11 Automatic Failover
With a license, a replica promotes itself when the primary goes down, with no manual step, and only when it can be done safely: it needs a majority of votes, no voter may still see the primary, the old primary is fenced, and the data is recent enough. Only the first live candidate in configuration order promotes.
-
Show the cluster ID and the license state:
ovios-shell ➤ ovios-cluster license -
Email the cluster ID to ovi@ovios.org and ask for a free 30-day test license. You receive a license file.
-
On the primary, install it. It is verified, installed and pushed to every node, and takes effect without a restart:
ovios-shell ➤ ovios-cluster license install acme.license -
On the primary, set
automatic_failover: truein the configuration and sync. This needs a quorum (a witness or tiebreaker) and afence_cmdon every data node, and is refused without a valid license:ovios-shell ➤ ovios-cluster sync -
Confirm with
ovios-cluster status: the Failover line should readautomatic=true (licensed).
A primary that cannot serve on the VIP. The primary checks every 30 seconds that the VIP
is assigned, that its link has a carrier, and, if you list vip_check_ports, that each of those
TCP ports accepts a connection. A problem is shown as DEGRADED: virtual IP: … in
status and in the ovios_cluster_vip_healthy metric. With automatic failover, a
problem that lasts vip_failure_seconds (default 60) makes the primary hand over to a healthy
replica using the same path as a planned switchover. The old primary is alive, so nothing is fenced and no
data is lost. Without automatic failover the problem is only reported.
If a license expires
An expiring license never stops a running primary or replication.
-
30 days before expiry:
statusand the log warn. Everything keeps working. -
After expiry, during the grace period (7 days by default, set per license): still works, with a louder warning.
-
After the grace period: automatic failover turns off and the cluster behaves as manual failover.
statusshows configured but NOT ACTIVE, andpromoteworks as usual. Installing a renewal re-enables it immediately.
Licenses are signed documents verified on your own systems, so no connection to us is needed. License terms are in the Terms & License.
12 After a Failover
Replication is asynchronous, so the old primary may hold writes that were never replicated. When it comes
back it demotes itself, and replication reports it as DIVERGED. Datasets are never overwritten
without an explicit decision from you.
-
Run
ovios-cluster statuson the new primary and find the diverged replica. -
Check what is on the old primary and decide whether any of that data should be kept.
-
Roll the old primary back and re-sync it from the new primary. This discards its divergent changes:
ovios-shell ➤ ovios-cluster resync 10.0.0.1 --discard-divergent-dataresyncaccepts a node's ID or its IP address.
Automatic rollback. If you would rather not run resync by hand, set
replication.auto_rollback: true. The primary then rolls back the node that was primary before it
(only that node, and only to the last common snapshot, never a full replace) when it returns. What that node
wrote after losing the role is discarded. A returning node that was not the previous
primary, or has no common snapshot, still needs resync.
Restarting the daemon never changes a node's role and never drops the VIP.
13 Command Reference
| Command | Where | Description |
|---|---|---|
init [--vip] [--tiebreaker] |
First node | Create a cluster; this node becomes the primary. |
add <ip> [--witness] [--fence-cmd CMD] |
Primary | Enrol a data node, or a vote-only witness. A data node needs a fence command while automatic failover is on. |
sync |
Primary | Validate the configuration and push it to every node. |
sync --check [--file F] |
Any node | Only validate (YAML, unknown keys, rules, license); pushes nothing. Used by
service ovios-cluster edit. |
status [--json] |
Any node | Show roles, quorum, peers, license and replication state. |
switchover [--host H] [--check] [-y] / --abort |
Primary | Planned, loss-free hand-over of the primary role to a replica. --check only rehearses,
--abort gives up a switchover that is still waiting for replication. |
promote [--force] |
The replica to take over | Manual failover, when the primary is down. |
demote [--force] |
The node to demote | Stop services, drop the VIP, unmount the datasets and set them readonly. --force is
needed if the cluster still names this node primary. |
resync <node> --discard-divergent-data |
Primary | Roll a diverged replica back and re-sync it. Discards its changes. |
push-archive <file.tar.gz> |
Primary | Extract a configuration archive on every other data node. |
license / license install <file> |
Primary | Show the cluster ID and license state, or install a license (it is pushed to every node). |
remove <node-id-or-ip> |
Primary | Remove a node from the cluster. |
destroy --yes [--all] |
Any node | Dismantle the cluster configuration on this node (with --all, every node). Your
datasets are kept. |
14 Key Options
Set in /etc/ovios-cluster/ovios-cluster.yaml on the primary, then run
ovios-cluster sync. Unknown keys are an error, so a misspelt option is not silently ignored. To
check a file without pushing it, run ovios-cluster sync --check.
| Option | Default | Description |
|---|---|---|
| Network and VIP | ||
vip |
none | The floating address that follows the primary, as an IP or in CIDR form. Needs interface. |
interface |
default route | Interface that carries the VIP. A node can override it with nodes[].interface. |
vip_check_ports |
none | TCP ports your clients use on the VIP (for example 3260, 445, 2049). The primary checks that each accepts a connection. Needs vip. |
vip_failure_seconds |
60 | How long VIP trouble may last before the primary hands over to a healthy replica (automatic failover only). Minimum 30. |
heartbeatport |
"9064" | Port of the mutual-TLS heartbeat, bound to the node's own address. |
| Failover | ||
automatic_failover |
false |
Licensed. Needs a quorum, a fence_cmd on every data node and at least two data nodes. |
heartbeat_interval |
2 s | Seconds between heartbeats and between engine ticks. |
lease_seconds |
15 | A primary without quorum steps down after this; a replica waits this plus half again before promoting. At least three times heartbeat_interval. |
max_replica_lag_seconds |
300 | promote, automatic failover and switchover refuse a replica whose newest replicated snapshot is older. |
tiebreaker |
none | An IP, such as the gateway, counted as an extra vote so a two-node cluster can tell a dead peer from a partition. |
nodes[].fence_cmd |
none | Shell command that powers the node off (for example ipmitool). Has 90 seconds. Required on every data node with automatic failover. A switchover or VIP hand-over never fences. |
| Replication | ||
datasets.exclude |
boot and root pools | Datasets that are never replicated. The receiving node refuses them too. |
replication.interval |
10 s | Seconds between replication cycles. |
replication.snapshot_prefix |
ovios |
Prefix of the snapshots the cluster creates and prunes. |
replication.workers |
4 | Transfers that run at the same time. |
replication.timeout_seconds |
3600 | Longest one dataset-to-node transfer may run. An interrupted transfer resumes from its token. |
replication.independent_datasets |
false |
Each dataset transfers on its own, so one huge dataset no longer delays the others. Keep workers at least as high as the number of datasets. |
replication.auto_rollback |
false |
Roll the previous primary back to the last common snapshot when it returns with writes that never reached the new primary. Those writes are discarded. |
replication.retention.keep_last |
12 | Newest snapshots kept. A node that is away keeps its base as a bookmark or a pinned snapshot, so it can catch up incrementally. |
| Services, hooks and monitoring | ||
services |
none | Units started in order on promotion and stopped in reverse on demotion. |
hooks |
none | pre_promote (a failure aborts), post_promote, pre_demote, post_demote. Run with OVIOS_NODE_ID, OVIOS_ROLE, OVIOS_EPOCH, OVIOS_VIP and OVIOS_CLUSTER set. |
metrics_listen |
off | Address of the Prometheus endpoint, for example ":9100". See Alerting and Metrics. |
binary_path |
/usr/bin/ovios-cluster |
Where the binary is on every node. The receive guard runs it over SSH. |
15 Alerting and Metrics
Every node can expose its cluster state as Prometheus metrics, so you can graph it and get
alerted before a problem reaches your clients. Metrics are free. All of them are gauges, and each carries the
label node="<this node's ID>".
Turn on the endpoint
Set metrics_listen in the cluster configuration on the primary, sync it, and restart the daemon
(a change of this option needs a restart). The endpoint is then http://<node>:9100/metrics.
# /etc/ovios-cluster/ovios-cluster.yaml
metrics_listen: ":9100"
ovios-shell ➤ ovios-cluster sync
ovios-shell ➤ service ovios-cluster restart # on every node
Mind what you bind to. 127.0.0.1:9100 answers only requests made on the node
itself, so a Prometheus server on another machine gets connection refused. The setting is part of the
cluster configuration, which is the same on every node, so use ":9100" (all addresses) rather
than one node's IP. The endpoint is plain HTTP without authentication, so restrict who can
reach the port with a firewall. Check that it listens with ss -ltn | grep 9100. 9100 is only an
example: use any free port.
Which metrics are exposed
This node
| Metric | Meaning |
|---|---|
ovios_cluster_epoch |
Current cluster epoch. |
ovios_cluster_is_primary |
1 if this node is the primary. |
ovios_cluster_role_applied |
1 if the machine matches the role in the cluster state (VIP, services and mounts as they should be). |
ovios_cluster_suspended |
1 if this primary stepped down after losing quorum. |
ovios_cluster_degraded |
1 if the node reports any degraded condition (failed services, VIP problem). |
ovios_cluster_votes_have |
Voters reachable, including this node. |
ovios_cluster_votes_total |
Total voters. |
ovios_cluster_quorum |
1 if a strict majority of voters is reachable. |
VIP
| Metric | Meaning |
|---|---|
ovios_cluster_vip_present |
1 if the VIP is configured on this node. Expect 1 on the primary and 0 on replicas. |
ovios_cluster_vip_healthy |
1 if there is no VIP problem: the address is assigned, the link has a carrier and every port in vip_check_ports answers. Always 1 on replicas. |
License
| Metric | Meaning |
|---|---|
ovios_cluster_license_autofailover |
1 if the license currently permits automatic failover. |
ovios_cluster_license_expiry_timestamp_seconds |
Unix time the license expires. Only present when a license is installed. |
Per peer
With the extra label peer="<id>": one series per other node, witness included.
| Metric | Meaning |
|---|---|
ovios_cluster_peer_up |
1 if an authenticated heartbeat from the peer arrived recently. |
ovios_cluster_peer_ssh_up |
1 if the peer's SSH port answers at its configured address. 0 means replication, switchover and sync to it will fail. Appears about 2 seconds after startup, then is checked every 30 seconds. |
ovios_cluster_peer_heartbeat_on_configured_address |
1 if the peer's heartbeats come from its configured address, 0 if from another one. Only present for alive peers. |
Replication
With the extra labels target="<node id>" and dataset="<name>". Meaningful on the primary.
| Metric | Meaning |
|---|---|
ovios_cluster_replication_lag_seconds |
Seconds since the last successful replication. -1 if it never succeeded. |
ovios_cluster_replication_diverged |
1 if the target holds data the primary does not and needs resync. |
ovios_cluster_replication_error |
1 if the last attempt failed. |
ovios_cluster_replication_props_error |
1 if the data is in sync but the properties could not be copied. |
Events are in the log, not in metrics. There are no counters for failovers, switchovers,
VIP hand-overs, fence calls or replication throughput. Those events are in the daemon log
(election.promote, promote.done, switchover.*,
vip.handover).
Peer status never triggers a failover. A peer counts as alive when an authenticated
heartbeat arrives from any address, so a single dead address does not cause a failover. But
replication, switchover, sync, add and remove use SSH to the node's
configured address, which can fail while heartbeats look fine. Alert on
ovios_cluster_peer_ssh_up and ovios_cluster_peer_heartbeat_on_configured_address
to catch that. For production, put the heartbeat on its own redundant network.
Set up Prometheus
OviOS can run the Prometheus service on the node itself: options prometheus.enable on starts it
now and at every boot (port 9090, manage it with service prometheus, configuration in
/etc/prometheus, which ships with a prometheus.yml). You can equally use a Prometheus
server elsewhere. Either way, it has to reach port 9100 of every node, witnesses
included.
Keep your Prometheus files in /etc/prometheus. That whole directory is
persisted across reboots, so it is the place for prometheus.yml, the alert rules file and any
other Prometheus file you add. Files saved anywhere else are lost at the next reboot of a stateless
(live) node.
-
Edit the
/etc/prometheus/prometheus.ymlthat ships with OviOS: add the nodes as a scrape job (underscrape_configs), and pointrule_filesat your rules:scrape_configs: - job_name: ovios-cluster scrape_interval: 15s static_configs: - targets: ['10.0.0.1:9100', '10.0.0.2:9100', '10.0.0.3:9100'] rule_files: - /etc/prometheus/rules/ovios-cluster.yml -
Save the alert rules below as
/etc/prometheus/rules/ovios-cluster.yml, inside the persisted/etc/prometheusdirectory. -
To be notified (email, chat, paging), point Prometheus at an Alertmanager. Without one, firing alerts are still shown on the Alerts page of Prometheus:
alerting: alertmanagers: - static_configs: - targets: ['alertmanager.example.com:9093'] -
Restart Prometheus and check that all targets are UP under Status → Targets:
ovios-shell ➤ service prometheus restart
Example alert rules
A starting point that covers quorum, roles, the VIP, peers, replication and the license. Adjust the
for: durations and thresholds to your environment. In particular, set the replication lag
threshold to match your max_replica_lag_seconds, and drop the license alerts if you run without a
license.
groups:
- name: ovios_cluster_alerts
rules:
# --- CLUSTER HEALTH & QUORUM ---
- alert: OviosClusterQuorumLost
expr: ovios_cluster_quorum == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Cluster quorum lost on node {{ $labels.node }}"
description: "A strict majority of voters is no longer reachable. Failover and write actions may fail."
- alert: OviosClusterMissingVoters
expr: ovios_cluster_votes_have < ovios_cluster_votes_total
for: 5m
labels:
severity: warning
annotations:
summary: "Cluster is missing active voters"
description: "Node {{ $labels.node }} reaches only {{ $value }} of its voters."
- alert: OviosClusterNoSinglePrimary
expr: sum(ovios_cluster_is_primary) != 1
for: 1m
labels:
severity: critical
annotations:
summary: "The cluster has no primary, or more than one"
description: "{{ $value }} nodes report that they are the primary."
- alert: OviosClusterNodeDegraded
expr: ovios_cluster_degraded == 1
for: 2m
labels:
severity: warning
annotations:
summary: "Node {{ $labels.node }} reports a degraded condition"
description: "Check ovios-cluster status and the daemon log on the node."
- alert: OviosClusterRoleMismatch
expr: ovios_cluster_role_applied == 0
for: 2m
labels:
severity: major
annotations:
summary: "Node role mismatch on {{ $labels.node }}"
description: "The local machine does not match the role assigned in the cluster state."
- alert: OviosClusterPrimarySuspended
expr: ovios_cluster_suspended == 1
for: 1m
labels:
severity: critical
annotations:
summary: "Primary suspended on {{ $labels.node }}"
description: "This primary has stepped down after losing quorum."
- alert: OviosClusterVipUnhealthy
expr: ovios_cluster_vip_healthy == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Node {{ $labels.node }} cannot serve clients on the VIP"
description: "The VIP is not assigned, its link has no carrier, or a checked port does not answer."
# --- PEER & CONNECTIVITY ---
- alert: OviosClusterPeerDown
expr: ovios_cluster_peer_up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Cluster peer {{ $labels.peer }} is down"
description: "Node {{ $labels.node }} has lost heartbeat connectivity to peer {{ $labels.peer }}."
- alert: OviosClusterPeerSSHDown
expr: ovios_cluster_peer_ssh_up == 0
for: 2m
labels:
severity: major
annotations:
summary: "Cluster peer {{ $labels.peer }} SSH unreachable"
description: "SSH to peer {{ $labels.peer }} failed from node {{ $labels.node }}. Replication and switchover will fail."
# --- REPLICATION & STORAGE ---
- alert: OviosReplicationError
expr: ovios_cluster_replication_error == 1
for: 5m
labels:
severity: major
annotations:
summary: "Replication error on dataset {{ $labels.dataset }}"
description: "Replication from {{ $labels.node }} to target {{ $labels.target }} is failing for dataset {{ $labels.dataset }}."
- alert: OviosReplicationDiverged
expr: ovios_cluster_replication_diverged == 1
for: 1m
labels:
severity: critical
annotations:
summary: "Replication diverged for dataset {{ $labels.dataset }}"
description: "{{ $labels.target }} holds data that {{ $labels.node }} does not. It needs resync."
- alert: OviosReplicationHighLag
expr: ovios_cluster_replication_lag_seconds > 3600
for: 10m
labels:
severity: warning
annotations:
summary: "High replication lag on dataset {{ $labels.dataset }}"
description: "Replication lag has exceeded 1 hour (currently {{ $value }} seconds)."
- alert: OviosReplicationNeverSucceeded
expr: ovios_cluster_replication_lag_seconds == -1
for: 10m
labels:
severity: warning
annotations:
summary: "Replication of {{ $labels.dataset }} has never succeeded"
description: "No successful replication of {{ $labels.dataset }} to {{ $labels.target }} yet."
# --- LICENSE ---
# Only useful if you hold a license: a free cluster always reports 0.
- alert: OviosLicenseNoAutoFailover
expr: ovios_cluster_license_autofailover == 0
for: 15m
labels:
severity: warning
annotations:
summary: "Automatic failover is not permitted by the license"
description: "The installed license, or the lack of one, does not permit automatic failover."
- alert: OviosLicenseExpiringSoon
expr: (ovios_cluster_license_expiry_timestamp_seconds - time()) < (30 * 24 * 3600)
for: 1h
labels:
severity: warning
annotations:
summary: "OviOS cluster license expires within 30 days"
description: "The license seen by node {{ $labels.node }} expires in less than 30 days. Please renew."
| Alert | What to do |
|---|---|
| Quorum lost, missing voters, peer down | Find the node or the network path that is down. A primary without quorum steps down by itself after
lease_seconds. |
| No single primary | Run ovios-cluster status on each node. With no primary, promote a
replica once you are sure the old one is down. Two primaries should not happen: the higher epoch wins. |
| Peer SSH unreachable | Fix SSH to the peer's configured address before you need a switchover or a sync. |
| VIP unhealthy, node degraded | Clients may not be able to connect. See the DEGRADED: line of status. |
| Replication error, high lag | Check the network and the daemon log. A replica that is too far behind is refused for failover. |
| Replication diverged | See After a Failover: decide what to keep, then resync. |
| License expiring | Install the renewal with ovios-cluster license install. It takes effect at once. |
16 Limits to Know
- Asynchronous replication. A failover can lose up to the replication interval plus the
cycle time of writes, bounded by
max_replica_lag_seconds. - Active/passive. One primary serves data at a time.
- IPv4 only for node addresses.
- Node certificates are valid for 5 years and are not rotated automatically.
- Root SSH. Nodes authenticate to each other over SSH with root's key.
- Clocks. License dates are checked against the node's clock, so keep time in sync.
17 Troubleshooting
| Symptom | Cause and fix |
|---|---|
add: "not installed on …" |
/usr/bin/ovios-cluster is missing on the new node. Install it there first. |
add: "zfs is not installed" |
The node is not a data node. Use --witness if it should only vote. |
add: "does not appear to be a local address" |
The IP you gave is not that host's own address. Check for NAT or a wrong address. |
| "destination pool … does not exist" | Create the pool, with the same name, on the replica. |
sync refuses the configuration |
Automatic failover needs a valid license, a quorum (witness or tiebreaker) and a
fence_cmd on every data node. |
promote refuses |
The primary is reachable, there is no quorum, another node still sees the primary, or the data is
too old. Fix the cause, or use --force only after confirming the old primary is down. |
switchover refuses |
The replica is unreachable, lags more than max_replica_lag_seconds, has divergence or
replication errors, or cannot confirm over SSH that it can take over. Run
switchover --check to see which. |
| A remote Prometheus gets "connection refused" | metrics_listen is 127.0.0.1:…. Use ":9100", then restart the
daemon. |
| Status shows "quorum not possible" | Add a witness or set a tiebreaker. |
| Status shows "Daemon is NOT running" | service ovios-cluster enable (or options cluster.enable on). Status falls back to the last known state from
disk. |
| Status shows "configured but NOT ACTIVE" | The license is missing, or expired past its grace period. Install or renew it. |
Want to see automatic failover work? Email ovi@ovios.org for a free 30-day test license.