我已经在 Btrfs 根分区上安装了 Ubuntu 20.04 以使用其快照功能。
为了尽可能简单,我想将 Btrfs 快照的创建集成到我的upgrade
-alias 命令中,目前如下所示:
sudo apt update && sudo apt upgrade -y && sudo flatpak update -y && sudo snap refresh
我该如何在更新之前最好地添加快照,以便如果出现任何问题我可以回滚?
是否还可以同时删除旧快照?(我的根分区已填充不到 10%,因此我可以多次复制整个系统,但我想它会随着每周更新而很快填满?)
答案1
我将基于Ignacio Nunez Hernanz 的精彩剧本:
#!/bin/bash
#
# Script that creates BTRFS snapshots, manually or from cron
#
# Usage:
# sudo btrfs-snp <dir> (<tag>) (<limit>) (<seconds>) (<destdir>)
#
# Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
# GPL licensed (see end of file) * Use at your own risk!
#
# Based on btrfs-snap by Birger Monsen
#
# More at https://ownyourbits.com
#
function btrfs-snp()
{
local BIN="${0##*/}"
local DIR="${1}"
local TAG="${2:-snapshot}"
local LIMIT="${3:-0}"
local TIME="${4:-0}"
local DST="${5:-.snapshots}"
## usage
[[ "$*" == "" ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] && {
echo "Usage: $BIN <dir> (<tag>) (<limit>) (<seconds>) (<destdir>)
dir │ create snapshot of <dir>
tag │ name the snapshot <tag>_<timestamp>
limit │ keep <limit> snapshots with this tag. 0 to disable
seconds │ don't create snapshots before <seconds> have passed from last with this tag. 0 to disable
destdir │ store snapshot in <destdir>, relative to <dir>
Cron example: Hourly snapshot for one day, daily for one week, weekly for one month, and monthly for one year.
cat > /etc/cron.hourly/$BIN <<EOF
#!/bin/bash
/usr/local/sbin/$BIN /home hourly 24 3600
/usr/local/sbin/$BIN /home daily 7 86400
/usr/local/sbin/$BIN /home weekly 4 604800
/usr/local/sbin/$BIN / weekly 4 604800
/usr/local/sbin/$BIN /home monthly 12 2592000
EOF
chmod +x /etc/cron.hourly/$BIN"
return 0
}
## checks
local SNAPSHOT=${TAG}_$( date +%F_%H%M%S )
[[ ${EUID} -ne 0 ]] && { echo "Must be run as root. Try 'sudo $BIN'" ; return 1; }
[[ -d "$SNAPSHOT" ]] && { echo "$SNAPSHOT already exists" ; return 1; }
mount -t btrfs | cut -d' ' -f3 | grep -q "^${DIR}$" || {
btrfs subvolume show "$DIR" | grep -q "${DIR}$" || {
echo "$DIR is not a BTRFS mountpoint or snapshot"
return 1
}
}
DST="$DIR/$DST"
mkdir -p "$DST"
local SNAPS=( $( btrfs subvolume list -s --sort=gen "$DST" | awk '{ print $14 }' | grep "${TAG}_" ) )
## check time of the last snapshot for this tag
[[ "$TIME" != 0 ]] && [[ "${#SNAPS[@]}" != 0 ]] && {
local LATEST=$( sed -r "s|.*_(.*_.*)|\\1|;s|_([0-9]{2})([0-9]{2})([0-9]{2})| \\1:\\2:\\3|" <<< "${SNAPS[-1]}" )
LATEST=$( date +%s -d "$LATEST" ) || return 1
[[ $(( LATEST + TIME )) -gt $( date +%s ) ]] && { echo "No new snapshot needed for $TAG"; return 0; }
}
## do it
btrfs subvolume snapshot -r "$DIR" "$DST/$SNAPSHOT" || return 1
## prune older backups
[[ "$LIMIT" != 0 ]] && \
[[ ${#SNAPS[@]} -ge $LIMIT ]] && \
echo "Pruning old snapshots..." && \
for (( i=0; i <= $(( ${#SNAPS[@]} - LIMIT )); i++ )); do
btrfs subvolume delete "$DIR/${SNAPS[$i]}"
done
echo "snapshot $SNAPSHOT generated"
}
btrfs-snp "$@"
# License
#
# This script is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this script; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
相关使用信息:
# btrfs-snp
Usage: btrfs-snp <dir> (<tag>) (<limit>) (<seconds>) (<destdir>)
dir │ create snapshot of <dir>
tag │ name the snapshot <tag>_<timestamp>
limit │ keep <limit> snapshots with this tag. 0 to disable
seconds │ don't create snapshots before <seconds> have passed from last with this tag. 0 to disable
destdir │ store snapshot in <destdir>, relative to <dir>
您的升级别名需要如下所示:
btrfs-snp / syschanges 3 600 && ...
生成带有标签的快照系统变更,但/.snapshots
如果过去 5 分钟内已经有一个,则不会,并且最多保留 3 个。
这为您提供了 5 分钟的时间来执行重复操作而不会造成混乱,例如,如果您想在一个安装步骤中从不同的 repos 或 ppa 安装,而不仅仅是升级。
然后,您可以按照 btrfs 最佳实践使用和恢复这些快照。
答案2
在 中制作快照非常容易btrfs
。
首先将包含文件系统的分区挂载btrfs
到例如/mnt
。我们假设它是/dev/sda1
。
sudo mount /dev/sda1 /mnt
cd /mnt
/
如果您有一个带有at@
和/home
at 的标准 Ubuntu 安装@home
,运行ls
将显示两个项目:@
和@home
。
此外,如果您之前创建了快照,它们也会显示在那里。
要创建和的快照/
,/home
请运行以下命令:
sudo btrfs sub snap @ @-BACKUP && sudo btrfs sub snap @home @home-BACKUP
如果您想在创建新备份之前删除现有备份,命令如下:
sudo btrfs sub del @-BACKUP && sudo btrfs sub del @home-BACKUP
就如此容易。
完成后,通过以下方式卸载分区/mnt
:
sudo umount /mnt
此外,我还可以补充一点,您可以创建带有时间戳的快照或进行增量备份。但这有点超出了问题的范围。
您可以将这些命令组合成一个文本文件,例如backup.sh
。
例子:
#!/bin/sh
mount /dev/sda1 /mnt
cd /mnt
[ -d @-BACKUP ] && sudo btrfs sub del @-BACKUP #Checks is backup exists and deletes it
[ -d @home-BACKUP ] && sudo btrfs sub del @home-BACKUP
btrfs sub snap @ @-BACKUP
btrfs sub snap @home @home-BACKUP
cd /
umount /mnt
该脚本应该使用 来运行sudo
。
答案3
我有几个想法要告诉你。挑选并组合。
- 专门构建的现成软件,例如apt-btrfs-快照或者etckeeper在后台自动完成这些工作。这可能是最好的方法了。
- 要复制上述软件包的自定义版本,您需要接入 apt每次更新后运行脚本。上面的软件包当然可以帮助您了解如何做到这一点的最佳实践,并在另一个答案。但它也可能是同样简单的事情
btrfs sub snapshot -r /mnt/btrfsroot/@/ /mnt/btrfsroot/snapshots/root-$(date +%y%m%d)
。 - 无论如何,虽然 apt/dpkg 有这样的钩子,但没有快照其他的我不太清楚。不过这应该不是什么问题,因为你首先按照你的问题运行了 apt。
- 您最终会得到许多快照,因此您还需要一种手动或自动删除过时快照的方法。为了让您了解如何做到这一点,假设您的自动快照具有以下路径,
/mnt/btrfsroot/snapshots/@*-apthook-YYMMDDHH
那么您将例如在每个月 12 日运行 cronjob34 03 12 * * btrfs sub delete /mnt/btrfsroot/snapshots/@*-apthook-$(date --date='15 days ago' +\%y\%m)*
。查看手册页man 5 crontab
和man date
了解更多信息。
我希望这能让你朝着正确的方向前进。同样,我建议你直接照做apt-btrfs-snapshot
就行了。请注意,截至目前,apt-btrfs-snapshot
假设您的根分区名为@
。这是 Ubuntu 和许多其他发行版的默认设置。
如果有什么不清楚的话,请随时询问后续问题。
/
PS:您是否了解(您正在运行的系统的根)和 btrfs-root之间的区别?
答案4
您可以使用此 shell 脚本轻松完成此操作。
创建一个包含以下内容的 shell 脚本:
# Directory for saving snapshots
SNAPDIR=/snapshots
export SNAPDIR
# Delete snapshots
sudo btrfs subvolume delete /mnt/btrfs/backup_*
# Ask user for the name of snapshot
echo -n "What will be the name of snapshot? "
read SNAPNAME
# Create the snapshot
sudo btrfs subvolume snapshot /mnt/btrfs/ $SNAPDIR/backup_$SNAPNAME
# Check if the snapshot created successfully, if not then exit
if [ $? -ne 0 ]
then
echo "Failed to create snapshot"
exit 1
fi
# Commands to execute after creating snapshot
sudo apt update && sudo apt upgrade -y && sudo flatpak update -y && sudo snap refresh
创建文件后,将 /snapshots 替换为所需的快照保存目录。然后将其放置在任何地方。
现在通过执行以下命令使其可执行:
chmod +x /path/to/shell/script.sh
现在更改升级别名的命令,以便它指向脚本。
现在运行您的别名将首先删除带有backup_
前缀的快照,然后它将对以 开头的名称保存的文件系统进行快照 backup_
。
请注意,首次运行时可能会显示错误。但请忽略它,因为首次运行时没有备份,因此无需删除任何内容。另外,不要在将backup_
保存备份快照的目录中创建名称以 at 开头的子卷或快照。这将导致在运行脚本时删除该目录。此外,快照不会包含来自其他快照、子卷和已安装分区的文件。