- Set up
sanoid on every node you want to send snapshots to.
- Enable the
epel repository:
sudo dnf install -y epel-release
- Install
git:
- Enable the
crb repository:
sudo dnf config-manager --enable crb
- Install the
sanoid dependency packages:
sudo dnf install -y perl-Config-IniFiles perl-Data-Dumper perl-Capture-Tiny perl-Getopt-Long lzop mbuffer mhash pv
- Clone the repository:
sudo git clone https://github.com/jimsalterjrs/sanoid.git
- Change directory into the
sanoid directory:
- Make the directory safe:
git config --global --add safe.directory /home/howard/sanoid
- Checkout the stable release:
sudo git checkout $(git tag | grep "^v" | tail -n 1)
- Install the executable binaries:
sudo cp sanoid syncoid findoid sleepymutex /usr/local/sbin
- Create the
sanoid configuration directory:
- Add the default
sanoid configuration:
sudo cp sanoid.defaults.conf /etc/sanoid
- Create a blank configuration file:
sudo touch /etc/sanoid/sanoid.conf
- Place an example configuration file in the directory:
sudo cp sanoid.conf /etc/sanoid/sanoid.example.conf
- Create the
sanoid systemd service:
```
cat « “EOF” | sudo tee /etc/systemd/system/sanoid.service
[Unit]
Description=Snapshot ZFS Pool
Requires=zfs.target
After=zfs.target
Wants=sanoid-prune.service
Before=sanoid-prune.service
ConditionFileNotEmpty=/etc/sanoid/sanoid.conf
[Service]
Environment=TZ=UTC
Type=oneshot
ExecStart=/usr/local/sbin/sanoid –take-snapshots –verbose
EOF
* Create one for the `sanoid` pruning service:
cat « “EOF” | sudo tee /etc/systemd/system/sanoid-prune.service
[Unit]
Description=Cleanup ZFS Pool
Requires=zfs.target
After=zfs.target sanoid.service
ConditionFileNotEmpty=/etc/sanoid/sanoid.conf
[Service]
Environment=TZ=UTC
Type=oneshot
ExecStart=/usr/local/sbin/sanoid –prune-snapshots –verbose
[Install]
WantedBy=sanoid.service
EOF
* Generate the `systemd` timer to execute `sanoid` every 15 minutes:
cat « “EOF” | sudo tee /etc/systemd/system/sanoid.timer
[Unit]
Description=Run Sanoid Every 15 Minutes
Requires=sanoid.service
[Timer]
OnCalendar=*:0/15
Persistent=true
[Install]
WantedBy=timers.target
EOF
* Update `systemd` on new service definitions:
sudo systemctl daemon-reload
* Enable the `sanoid` `prune` service:
sudo systemctl enable sanoid-prune.service
* Enable and start the `sanoid` timer:
sudo systemctl enable –now sanoid.timer
* Generate an `ssh` key on each machine you wish to share snapshots with, including the original machine:
ssh-keygen -b 4096
Create the public/private key pair under:
/home//.ssh/id_rsa
Do not set a password.
* Share `ssh` keys between all machines that you want to transfer snapshots from and to:
ssh-copy-id @
* To ensure `syncoid` can push to and pull from a remote host, allow `zfs` to be ran without `sudo`.
* Check the binary location of `zfs`:
which zfs
* Edit the `/etc/sudoers` file:
sudo visudo
* Add the following line:
Allow the zfs binary to be executed without sudo
ALL=NOPASSWD:
```
* Create a `systemd` timer to sync snapshots on the remote host from the source host:
```
sudo tee -a /etc/systemd/system/syncoid.service << EOF
[Unit]
Description=Create and send snapshots from the source host to the remote host.
After=network.target
[Service]
ExecStart=/home/howard/scripts/syncoid.sh
Type=oneshot
User=howard
EOF
```
* Make a `timer` service file for `syncoid`:
```
sudo tee -a /etc/systemd/system/syncoid.timer << EOF
[Unit]
Description=Pull from source and create snapshots every day.
[Timer]
OnCalendar=*-*-* 00:00:00
[Install]
WantedBy=timers.target
EOF
```
* Enable the `timer`:
```
sudo systemctl enable syncoid.timer
```
* Start the `timer`:
```
sudo systemctl start syncoid.timer
```
* Create a `scripts` directory:
```
mkdir ~/scripts
```
* Make a script that the `systemd` service will then run:
```
tee -a ~/scripts/syncoid.sh <<EOF
#!/bin/bash
syncoid -r howard@192.168.1.101:sonic/anime tails/anime
syncoid -r howard@192.168.1.101:sonic/bitcoin tails/bitcoin
syncoid -r howard@192.168.1.101:sonic/children_shows tails/children_shows
syncoid -r howard@192.168.1.101:sonic/dance_videos tails/dance_videos
syncoid -r howard@192.168.1.101:sonic/documents tails/documents
syncoid -r howard@192.168.1.101:sonic/ebooks tails/ebooks
syncoid -r howard@192.168.1.101:sonic/films tails/films
syncoid -r howard@192.168.1.101:sonic/games tails/games
syncoid -r howard@192.168.1.101:sonic/gaming_videos tails/gaming_videos
syncoid -r howard@192.168.1.101:sonic/isos tails/isos
syncoid -r howard@192.168.1.101:sonic/linux tails/linux
syncoid -r howard@192.168.1.101:sonic/live_shows tails/live_shows
syncoid -r howard@192.168.1.101:sonic/music tails/music
syncoid -r howard@192.168.1.101:sonic/photos tails/photos
syncoid -r howard@192.168.1.101:sonic/shows tails/shows
syncoid -r howard@192.168.1.101:sonic/skateboarding tails/skateboarding
syncoid -r howard@192.168.1.101:sonic/software tails/software
EOF
```
* Make the script executable:
```
chmod +x ~/scripts/syncoid.sh
```
* Reload the `systemd` services:
```
sudo systemctl daemon-reload
```
* Disable SELinux:
```
sudo setenforce permissive
sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
```
* Install `tmux`:
```
sudo dnf install -y tmux
```
* Start a `tmux` session:
```
tmux
```
* Start the service:
```
sudo systemctl start syncoid
```
* Pull snapshots from the source. Run this on the nodes that are pulling the snapshots:
```
syncoid -r howard@192.168.1.101:sonic/linux tails/linux
```
* List all snapshots available on the node:
```
zfs list -t snapshot
zfs list -rt all
```
* Destroy a snapshot:
```
zfs destroy pool/dataset/snapshot
```
* Apply the following `/etc/sanoid/sanoid.conf` file:
```
sudo tee /etc/sanoid/sanoid.conf <<EOF
[version]
version = 2
[template_tails]
# these settings don't make sense in a template, but we use the defaults file
# as our list of allowable settings also, so they need to be present here even if
# unset.
path =
recursive =
use_template =
process_children_only =
skip_children =
# See "Sanoid script hooks" in README.md for information about scripts.
pre_snapshot_script =
post_snapshot_script =
pre_pruning_script =
pruning_script =
script_timeout = 5
no_inconsistent_snapshot =
force_post_snapshot_script =
# for snapshots shorter than one hour, the period duration must be defined
# in minutes. Because they are executed within a full hour, the selected
# value should divide 60 minutes without remainder so taken snapshots
# are apart in equal intervals. Values larger than 59 aren't practical
# as only one snapshot will be taken on each full hour in this case.
# examples:
# frequent_period = 15 -> four snapshot each hour 15 minutes apart
# frequent_period = 5 -> twelve snapshots each hour 5 minutes apart
# frequent_period = 45 -> two snapshots each hour with different time gaps
# between them: 45 minutes and 15 minutes in this case
frequent_period = 15
# If any snapshot type is set to 0, we will not take snapshots for it - and will immediately
# prune any of those type snapshots already present.
#
# Otherwise, if autoprune is set, we will prune any snapshots of that type which are older
# than (setting * periodicity) - so if daily = 90, we'll prune any dailies older than 90 days.
autoprune = yes
frequently = 0
hourly = 0
daily = 60
weekly = 0
monthly = 0
yearly = 0
# pruning can be skipped based on the used capacity of the pool
# (0: always prune, 1-100: only prune if used capacity is greater than this value)
prune_defer = 0
# We will automatically take snapshots if autosnap is on, at the desired times configured
# below (or immediately, if we don't have one since the last preferred time for that type).
#
# Note that we will not take snapshots for a given type if that type is set to 0 above,
# regardless of the autosnap setting - for example, if yearly=0 we will not take yearlies
# even if we've defined a preferred time for yearlies and autosnap is on.
autosnap = 0
# hourly - top of the hour
hourly_min = 0
# daily - at 23:59 (most people expect a daily to contain everything done DURING that day)
daily_hour = 23
daily_min = 59
# weekly -at 23:30 each Monday
weekly_wday = 1
weekly_hour = 23
weekly_min = 30
# monthly - immediately at the beginning of the month (ie 00:00 of day 1)
monthly_mday = 1
monthly_hour = 0
monthly_min = 0
# yearly - immediately at the beginning of the year (ie 00:00 on Jan 1)
yearly_mon = 1
yearly_mday = 1
yearly_hour = 0
yearly_min = 0
# monitoring plugin - define warn / crit levels for each snapshot type by age, in units of one period down
# example hourly_warn = 90 means issue WARNING if most recent hourly snapshot is not less than 90 minutes old,
# daily_crit = 36 means issue CRITICAL if most recent daily snapshot is not less than 36 hours old,
# monthly_warn = 5 means issue WARNING if most recent monthly snapshot is not less than 5 weeks old... etc.
# the following time case insensitive suffixes can also be used:
# y = years, w = weeks, d = days, h = hours, m = minutes, s = seconds
#
# monitor_dont_warn = yes will cause the monitoring service to report warnings as text, but with status OK.
# monitor_dont_crit = yes will cause the monitoring service to report criticals as text, but with status OK.
#
# setting any value to 0 will keep the monitoring service from monitoring that snapshot type on that section at all.
monitor = no
monitor_dont_warn = no
monitor_dont_crit = no
frequently_warn = 0
frequently_crit = 0
hourly_warn = 90m
hourly_crit = 360m
daily_warn = 28h
daily_crit = 32h
weekly_warn = 0
weekly_crit = 0
monthly_warn = 32d
monthly_crit = 40d
yearly_warn = 0
yearly_crit = 0
# default limits for capacity checks (if set to 0, limit will not be checked)
# for overriding these values one needs to specify them in a root pool section! ([tank]\n ...)
capacity_warn = 80
capacity_crit = 95
EOF
```