PVE 备份快照 - 知乎
抄一个备份
vmware压缩整个虚拟机文件夹就可以连带快照一起打包。
PVE 自带的vzdump备份并不包含快照信息,备份之后再还原,会丢失快照信息。
备份时提示:snapshots found (not included into backup)
快照信息在循序渐进的开发模式中十分重要,遇到错误直接回退即可。
本文提供一套连带快照打包思路。PVE虚拟机的完全打包,需要关注两个目录:
1.虚拟机配置存放目录: /etc/pve/qemu-server/
2.虚拟机磁盘存放目录:/var/lib/vz/images(默认)或其他设备对应目录。
本文存放磁盘设备为(/mnt/SSD-1T/images),磁盘设备使用qcow2格式。
例如,完全备份id为101的虚拟机,只需要备份 /etc/pve/qemu-server/101.conf 和 /mnt/SSD-1T/images/101 即可。
101.conf里保存了该虚拟机的硬件配置、快照信息以及磁盘目录。
/mnt/SSD-1T/images/101 下存放了被该虚拟机指向的磁盘。
磁盘文件为稀疏文件模式,例如120G的磁盘初始占用只有44G。
为保证磁盘打包前后都保持稀疏模式,打包方法建议使用 tar命令 加-S参数。
注意,其他打包方式可能导致稀疏属性丢失,解包后占用空间为磁盘最大值。
打包命令参考:
tar -czSvf /mnt/HDD-4T/101.tar /mnt/SSD-1T/images/101
传统tar单线程打包压缩速度过慢,建议使用pigz并行压缩打包,结合pv管道统计进度:
需额外安装:apt install pigz pv -y
tar -cSf - /mnt/SSD-1T/images/101 | pv -s $(du -s /mnt/SSD-1T/images/101 | awk '{print $1}' | xargs -I {} echo "scale=0; {} * 1024" | bc) | pigz > /mnt/HDD-4T/101.tar.gz
使用示例
支持交互模式,按提示输入
./backup.sh
./resume.sh
也支持单条调用模式,备份示例,参数: 需备份id , 备份文件名 , 无需确认 :
./backup.sh 101 ubt22_test yes
还原示例, 参数:备份文件路径,还原id , 无需确认 :
./resume.sh /mnt/HDD-4T/hand_back/ubt22_test.tar.gz 120 yes
备份示例:
示例还原:
#备份 #!/usr/bin/zsh #配置目录 conf_dir='/etc/pve/qemu-server'#磁盘目录,改为自己机器实际目录 disk_dir='/mnt/SSD-1T/images' #备份存储目录,改为自己机器实际目录 back_dir='/mnt/HDD-4T/hand_back'vmid=$1 back_name=$2 confirm=$3if [ -z "$vmid" ] || [ -z "$back_name" ]; thenecho '已有虚拟机id和name映射如下:'grep 'name:' -r $conf_direcho "\n"echo "请输入需备份vmid,如(101):"read vmidecho "你输入的vmid是:$vmid,配置如下:"cat $conf_dir/$vmid.confecho "\n"echo "该虚拟机磁盘占用信息:"ls -lh $disk_dir/$vmidecho "存储备份文件夹为:$back_dir"echo "存储文件夹已有文件列表如下:"ls -lh $back_dir/*.tar.gzecho "\n"echo "请输入存储备份文件名(不包含.tar.gz后缀),如(ubt22_init):"read back_name fiecho "目标存储文件为$back_dir/$back_name.tar.gz" if [ -e "$back_dir/$back_name.tar.gz" ]; thenecho "目标文件已存在,需再次手动确认是否覆盖:"ls -lh $back_dir/$back_name.tar.gzconfirm="" fiif [ "$confirm" != "yes" ]; thenwhile true; doecho "确认开始备份 $disk_dir/$vmid -> $back_dir/$back_name.tar.gz 吗?"echo "输入yes或no" read confirmcase "$confirm" in"yes")echo "你输入了yes,准备开始备份..."break;;"no")echo "你输入了no,脚本即将结束。"exit 0;;*)echo "输入不合法,请输入yes或no。"continue;;esacdone fi#记录开始时间 start_time=$(date +"%Y-%m-%d %H:%M:%S") echo "$start_time,开始备份操作:"#备份配置文件 cp $conf_dir/$vmid.conf $disk_dir/$vmid/ echo "复制配置完成:cp $conf_dir/$vmid.conf $disk_dir/$vmid/,开始打包:"#打包,-S 保留稀疏结构 echo "切换到:cd $disk_dir,开始备份打包:" cd $disk_dir tar -cSf - $vmid | pv -s $(du -s $vmid | awk '{print $1}' | xargs -I {} echo "scale=0; {} * 1024" | bc) | pigz > $back_dir/$back_name.tar.gz echo "备份打包完成:ls -lh $back_dir/$back_name.tar.gz" ls -lh $back_dir/$back_name.tar.gz#summary end_time=$(date +"%Y-%m-%d %H:%M:%S") start=$(date +%s --date="$start_time") end=$(date +%s --date="$end_time") diff_in_seconds=$((end - start))# 进行单位换算 hours=$((diff_in_seconds / 3600)) remaining_seconds=$((diff_in_seconds % 3600)) minutes=$((remaining_seconds / 60)) remaining_seconds=$((remaining_seconds % 60))# 输出操作耗费时间和当前时间 echo "耗时:$hours 小时 $minutes 分 $remaining_seconds 秒" echo "$end_time,备份结束"
#还原 #!/usr/bin/zsh#配置目录 conf_dir='/etc/pve/qemu-server'#磁盘目录,改为自己机器实际目录 disk_dir='/mnt/SSD-1T/images' #备份存储目录,改为自己机器实际目录 back_dir='/mnt/HDD-4T/hand_back'back_name=$1 vmid=$2 confirm=$3if [ -z "$vmid" ] || [ -z "$back_name" ]; thenecho '已有虚拟机id和name映射如下:'grep 'name:' -r $conf_direcho "\n"echo '已有虚拟机磁盘如下:'ls "$disk_dir/"echo "\n"echo "存储备份文件夹为:$back_dir"echo "存储文件夹已有备份列表如下:"ls -lh $back_dir/*.tar.gzecho "\n"echo "请输入需还原文件(完整路径):"read back_nameif [ ! -e "$back_name" ]; thenecho "输入备份:$back_name 不存在,请检查后再试"exit 0fiecho "请输入还原vmid,如(101):"read vmidif [ -e "$conf_dir/$vmid.conf" ] || [ -e "$disk_dir/$vmid" ]; thenecho "目标vmid已存在,请检查后再试"du -hd1 "$conf_dir/$vmid.conf"du -hd1 "$disk_dir/$vmid/"exit 0fi fiif [ "$confirm" != "yes" ]; thenwhile true; doecho "确认开始还原 $back_name -> $disk_dir/$vmid -> 吗?"echo "输入yes或no" read confirmcase "$confirm" in"yes")echo "你输入了yes,准备开始还原..."break;;"no")echo "你输入了no,脚本即将结束。"exit 0;;*)echo "输入不合法,请输入yes或no。"continue;;esacdone fi#记录开始时间 start_time=$(date +"%Y-%m-%d %H:%M:%S") echo "$start_time,开始还原操作:"#设置临时文件夹, tmp_dir=$disk_dir/resume_tmpif [ ! -d "$tmp_dir" ]; thenmkdir "$tmp_dir" fi#解压缩至临时文件夹 pv $back_name | tar -xzf - -C $tmp_dir#解压后唯一文件夹名即为id; old_id=`ls $tmp_dir|tail -n1`echo "conf 替换id:$old_id -> $vmid"#本处只做简单的vmid匹配替换。默认备份与还原的存储容器一致,如非一致,请手动修改vmid.conf 中磁盘路径的配置。#只替换目录名,保留原磁盘文件名, cp $tmp_dir/$old_id/$old_id.conf $tmp_dir/$old_id/$old_id.conf.tmp sed "s/vm-$old_id/vm-$vmid/g; s/:$old_id\//:$vmid\//g" $tmp_dir/$old_id/$old_id.conf.tmp > $tmp_dir/$old_id/$old_id.conf#清除临时文件 rm $tmp_dir/$old_id/$old_id.conf.tmpecho "重命令磁盘vmid:$old_id -> $vmid" #重命名磁盘文件 for file in $tmp_dir/$old_id/*$old_id*.qcow2; donew_file=$(echo "$file" | sed "s/-$old_id-/-$vmid-/g")mv "$file" "$new_file" doneecho "替换完毕,移动至正式目录:mv $tmp_dir/$old_id $disk_dir/$vmid" mv $tmp_dir/$old_id $disk_dir/$vmid mv $disk_dir/$vmid/$old_id.conf $disk_dir/$vmid/$vmid.conf cp $disk_dir/$vmid/$vmid.conf $conf_dir/$vmid.confls -lh $disk_dir/$vmid ls -lh $conf_dir/$vmid.conf#summary end_time=$(date +"%Y-%m-%d %H:%M:%S") start=$(date +%s --date="$start_time") end=$(date +%s --date="$end_time") diff_in_seconds=$((end - start))# 进行单位换算 hours=$((diff_in_seconds / 3600)) remaining_seconds=$((diff_in_seconds % 3600)) minutes=$((remaining_seconds / 60)) remaining_seconds=$((remaining_seconds % 60))# 输出操作耗费时间和当前时间 echo "耗时:$hours 小时 $minutes 分 $remaining_seconds 秒" echo "$end_time,还原结束"