前言
服务器系统使用的btrfs
文件系统,之前配置的时候没记录,迁移系统的时候差点忘记了,故回顾之后赶紧记录下来。
需求
定时对系统盘进行快照,将快照保存到系统盘/.snapshots/autosnapshots
,并增量备份到另外一个btrfs文件系统的磁盘/data/.snapshots/autosnapshots
中。
- 24小时内,保留每3小时的快照
- 最近半个月,每天至少保留一份快照
- 最近4个月,每周至少保留一份快照
- 最近12个月,每月至少保留一份快照
- 每年至少保留一份快照
功能实现
安装btrbk
sudo apt install btrbk
修改btrbk配置文件
/etc/btrbk.conf
transaction_log /var/log/btrbk.log
# 本地快照存储路径
snapshot_dir /.snapshots/autosnapshots
snapshot_preserve 72h 14d 12w 12m *y
# 远程备份目标路径(另一块Btrfs磁盘)
target /data/.snapshots/autosnapshots
target_preserve 72h 14d 12w 12m *y
# 需要备份的子卷配置
subvolume /
subvolume /home
subvolume /var/cache
subvolume /var/log
配置定时服务
/etc/systemd/system/btrbk.service
[Unit]
Description=btrbk Backup Service
[Service]
Type=oneshot
ExecStart=/usr/bin/btrbk run
/etc/systemd/system/btrbk.timer
[Unit]
Description=Run btrbk every 3 hours
[Timer]
OnCalendar=*-*-* 0/3:00:00
Persistent=true
[Install]
WantedBy=timers.target
启动服务
sudo systemctl daemon-reload
sudo systemctl enable --now btrbk.timer
其他
同时还写了份手动快照备份的脚本,脱离于btrbk架构实现本地和跨设备增量备份功能。
manusnapshot.sh
#!/bin/bash
set -euo pipefail
# ========== 配置:挂载路径与子卷名称的映射 ==========
declare -A mount_map=(
[@ubuntu]="/"
[@home]="/home"
[@cache]="/var/cache"
[@log]="/var/log"
[@tmp]="/tmp"
[@swap]="/swap"
[@snapshots]="/.snapshots"
)
# ========== 生成时间戳 ==========
timestamp=$(date +"%Y%m%dT%H%M")
local_snap_root="/.snapshots/manusnapshots"
remote_snap_root="/data/.snapshots/manusnapshots"
local_snap_dir="$local_snap_root/$timestamp"
remote_snap_dir="$remote_snap_root/$timestamp"
sudo mkdir -p "$local_snap_dir"
sudo mkdir -p "$remote_snap_dir"
# ========== 对每个子卷进行快照和备份 ==========
for subvol in "${!mount_map[@]}"; do
mount_path="${mount_map[$subvol]}"
local_snap_path="$local_snap_dir/$subvol"
remote_snap_path="$remote_snap_dir/$subvol"
echo "📦 正在为 $mount_path 创建快照 $local_snap_path ..."
sudo btrfs subvolume snapshot -r "$mount_path" "$local_snap_path"
# 查找上一快照用于增量
last_snap=$(find "$local_snap_root" -mindepth 2 -maxdepth 2 -type d -name "$subvol" | sort | tail -n 2 | head -n 1)
echo "📤 正在发送快照 $subvol 到 $remote_snap_dir ..."
if [[ -n "$last_snap" && "$last_snap" != "$local_snap_path" ]]; then
echo "➡️ 使用增量发送:$last_snap -> $local_snap_path"
sudo btrfs send -p "$last_snap" "$local_snap_path" | sudo btrfs receive "$remote_snap_dir"
else
echo "⬇️ 无前一个快照,执行全量发送"
sudo btrfs send "$local_snap_path" | sudo btrfs receive "$remote_snap_dir"
fi
done
echo "✅ 所有子卷快照与同步完成:$timestamp"