コンテンツにスキップ

RAID 1

中古HDDを2台購入したが、すぐ壊れると思われる。そこで、普段は片方を使用し、もう片方をその複製として使用することにした(RAID 1)。

もう少し高度なRAIDは将来の楽しみとして残しておく。

これが↓(sdb1が普段使い、sdc2がバックアップ担当)

❯ dysk
┌─────────────────────────────────┬───────┬────┬────┬─────────┬────┬────┬───────────┐
│ filesystem │ type │disk│used│ use │free│size│mount point│
├─────────────────────────────────┼───────┼────┼────┼─────────┼────┼────┼───────────┤
...
│/dev/sdb1 │fuseblk│HDD │ 71G│14% ▊ │429G│500G│/mnt/hdd │
│/dev/sdc2 │fuseblk│HDD │112M│ 0% │500G│500G│/mnt/hdd2 │
...
└─────────────────────────────────┴───────┴────┴────┴─────────┴────┴────┴───────────┘

こう↓

❯ dysk
┌─────────────────────────────────┬───────┬────┬────┬─────────┬────┬────┬───────────┐
│ filesystem │ type │disk│used│ use │free│size│mount point│
├─────────────────────────────────┼───────┼────┼────┼─────────┼────┼────┼───────────┤
...
│/dev/sdb1 │fuseblk│HDD │ 71G│14% ▊ │429G│500G│/mnt/hdd │
│/dev/sdc2 │fuseblk│HDD │ 71G│14% ▊ │429G│500G│/mnt/hdd2 │
...
└─────────────────────────────────┴───────┴────┴────┴─────────┴────┴────┴───────────┘

dry run

実際に変更せず、変更内容を確認。

rsyncコマンドはパスの末尾 / の有無で挙動が変わるので注意。

Terminal window
sudo rsync -a \
--delete-delay \
--partial \
--itemize-changes \
--dry-run \
/mnt/hdd/ /mnt/hdd2/

run

Terminal window
sudo rsync -a \
--delete-delay \
--partial \
--info=progress2 \
/mnt/hdd/ /mnt/hdd2/

自動実行

UUIDはlsblk --fsfindmnt -rn -o UUID -M /mnt/pathから取得。

mirror-disks
#!/usr/bin/env bash
set -euo pipefail
# TODO
readonly src=/mnt/hdd
readonly dst=/mnt/hdd2
readonly expected_src_uuid="SOURCE-UUID"
readonly expected_dst_uuid="DESTINATION-UUID"
findmnt -rn -M "$src" >/dev/null || {
echo "Error: $src is not mounted" >&2
exit 1
}
findmnt -rn -M "$dst" >/dev/null || {
echo "Error: $dst is not mounted" >&2
exit 1
}
actual_src_uuid=$(findmnt -rn -o UUID -M "$src")
actual_dst_uuid=$(findmnt -rn -o UUID -M "$dst")
[[ "$actual_src_uuid" == "$expected_src_uuid" ]] || {
echo "Error: unexpected source UUID: $actual_src_uuid" >&2
exit 1
}
[[ "$actual_dst_uuid" == "$expected_dst_uuid" ]] || {
echo "Error: unexpected destination UUID: $actual_dst_uuid" >&2
exit 1
}
# 同時実行防止
exec 9>/run/mirror-disks.lock
flock -n 9 || {
echo "Error: another mirror process is running" >&2
exit 1
}
echo "Mirror started: $(date --iso-8601=seconds)"
rsync -a \
--delete-delay \
--partial-dir=.rsync-partial \
--itemize-changes \
--human-readable \
"$src/" "$dst/"
sync -f "$dst"
echo "Mirror completed: $(date --iso-8601=seconds)"
Terminal window
sudo install -m 0755 mirror-disks /usr/local/sbin/mirror-disks
# sudo /usr/local/sbin/mirror-disks # 実行

systemd

service作成

Terminal window
sudoedit /etc/systemd/system/mirror-disks.service
Terminal window
[Unit]
Description=Mirror /mnt/hdd to /mnt/hdd2
After=local-fs.target
RequiresMountsFor=/mnt/hdd /mnt/hdd2
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/mirror-disks
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7

timer作成

Terminal window
sudoedit /etc/systemd/system/mirror-disks.timer
  • PC起動から10分後に実行
  • 前回の処理終了から24時間後に再実行
Terminal window
[Unit]
Description=Run disk mirror periodically
[Timer]
OnBootSec=10min
OnUnitInactiveSec=24h
AccuracySec=5min
Unit=mirror-disks.service
[Install]
WantedBy=timers.target

実行

Terminal window
sudo systemctl daemon-reload
sudo systemctl start mirror-disks.service
Terminal window
systemctl status mirror-disks.service

有効化

Terminal window
sudo systemctl enable --now mirror-disks.timer
systemctl list-timers mirror-disks.timer
# 無効化
# sudo systemctl disable --now mirror-disks.timer