树莓派镜像压缩

参考链接:https://neucrack.com/p/107
https://www.hao4k.cn/thread-41764-1-1.html(加精)

1 查看SD卡设备号

​ 将树莓派SD卡插上电脑,映射到虚拟机,使用下面命令获取SD卡设备号

sudo lsblk

在这里插入图片描述

​ 从上面可以看出,SD卡被识别为了sdb,分为sdb1和sdb2,

2 修改脚本文件

​ 修改“bachup_system.sh”脚本文件,把上面读到的两个挂载地址分别赋给src_boot_device、src_root_device、src_boot_device_blkid、src_root_device_blkid,如下图所示

#!/bin/bash
#
# backup script for raspberry Pi, backup on PC in recommend
# usage:
#       1. Cleanup your unuseful files in system
#       2. Reboot to check system can normally boot
#       3. Shutdown and remove TF card from Pi, and put it in a card reader
#       4. Plug your card reader into a PC's USB port
#       5. PC's OS should be ubuntu(recommend)/dedian/arch/manjaro
#       6. Edit the TODO section below, find your device by `sudo lsblk` command
#       7. Execute script, the script will automatically install software and print size,
#          ensure your PC have enough place
#       8. wait and see if error occurrs, if error occurrs,
#          see error carefully and maybe you can change config to resolve it
#
#       9. If error occurred, you can manually umount virual device by
#          `df -h` to see mount info, then `sudo umount dir`
#          `sudo blkid`, then `sudo kpartx -d /dev/loopx && sudo losetup -d /dev/loopx`
# recover:
#        1. Burn image to TF card by `sudo dd if=backup.img of=/dev/sdx status=progress bs=1MiB`
#                                    or other tools like etcher, win32diskimager etc.
#        2. Expand filesystem
#               way1: boot system on Pi and switch to console by `ctrl+alt+F1`, 
#                     login and execute `sudo raspi-config`, in `advanced config` select `expand filesystem`, `reboot`, all things done
#               way2: use gparted GUI tool to expand filesystem              
# author: neucrack (neucrack.com)
# update: 2021-04-26 optimize backup
#


set -o errexit
######################################################
################## TODO: settings#####################
src_boot_device=/dev/sdb1         #/dev/mmcblk0p1
src_root_device=/dev/sdb2         #/dev/root
src_boot_device_blkid=/dev/sdb1   #/dev/mmcblk0p1
src_root_device_blkid=/dev/sdb2   #/dev/mmcblk0p2

root_backup_size=1.3              # root backup size, 1 means the same as used size
os_arch_manjaro=0                 # for system Arch or Manjaro, else ubuntu/debian
backup_on_pi=0                 # 1: backup on pi(maybe not well supported), 0: backuo on PC (recommend)
# !!!!!if back on PI, it's better to use rsync
copy_use_rsync=0               # 1: use rsync to copy files, 0: use dump command to copy files
# !!!!!if back on PI, you should umount all your disk devices like USB disk or add exclude here
# rsync_exlude='--exclude relative_path1 --exclude relative_path2'
rsync_exlude='--exclude home/pi/data/raid'
######################################################


green="\e[32;1m"
yellow="\e[33;1m"
red="\e[31;1m"
purple="\e[35;1m"
normal="\e[0m"

# check
if [ "${backup_on_pi}x" == "1x" ]; then
  echo "====================="
  echo -e "${green}backup on pi${normal}"
  echo "====================="
  root_uid=`sudo cat /etc/passwd | grep root|awk -F : '{print $3}'`
  root_gid=`sudo cat /etc/passwd | grep root|awk -F : '{print $4}'`
  if [ "${root_uid}x" != "${root_gid}x" ]; then
    echo "root user(uid:${root_uid}, gid:${root_gid}) must belong to root group, change by sudo usermod -g root root"
    exit 1
  fi
else
  echo "====================="
  echo -e "${green}backup on PC${normal}"
  echo "====================="
fi

echo -e "${green} \ninstall software\n ${normal}"
if [ "${os_arch_manjaro}x" == "1x" ]; then
  echo "-- install by pacman"
  sudo pacman -S dosfstools parted multipath-tools bc
else
  sudo apt-get install -y dosfstools dump parted kpartx bc
fi
echo -e "${green} \ninstall software complete\n ${normal}"

echo -e "before backup, it's better to clean your temp files and not useful files, and carefully, not detele useful data!!!"
if [ "${os_arch_manjaro}x" != "1x" ]; then
  if [ "${backup_on_pi}x" == "1x" ]; then
    echo -e "${gren} \nclean apt cache\n${normal}"
    sudo apt-get autoremove -yq --purge
    sudo apt-get clean
    sudo rm -rf /var/lib/apt/lists/*
    sudo rm -rf /tmp/*
  fi
fi

if [ "${backup_on_pi}x" != "1x" ]; then
  echo -e "${green} mount ${normal}"
  sudo mkdir -p /media/backup_src_boot
  sudo mkdir -p /media/backup_src_root
  if df -P | grep $src_boot_device_blkid ; then
    echo "already mounted"
  else
    sudo mount $src_boot_device_blkid /media/backup_src_boot
    sudo mount $src_root_device_blkid /media/backup_src_root
  fi
  echo -e "${green} mount ok ${normal}"
fi

echo -e "${green}create image now\n ${normal}"
used_size=`df -P | grep $src_root_device | awk '{print $3}'`
boot_size=`df -P | grep $src_boot_device | awk '{print $2}'`
if [ "x${used_size}" != "x" ] && [ "x${boot_size}" != "x" ];then
        count=`echo "${used_size}*${root_backup_size}/1024+${boot_size}/1024+2"|bc|awk '{printf("%.0f",$1)}'`
else
        echo "device $src_root_device or $src_boot_device not exist in `df -P`,mount first"
        exit 0;
fi
echo -e "${green}boot size:$(($boot_size/1024+1))MiB, root used_size:$(($used_size/1024)) MiB, will backup as: $count MiB ${normal}"
echo -e "${purple}If your mem > used_size, it's a faster way to backup in tempfs directory~~~${normal}"
echo -e "${yellow}continue? yes or no${normal}"


read x
case "$x" in 
   y|yes ) echo "#########";;
   n|no  ) exit 1;;
   * ) echo "Only answer yes or no!"
esac

echo -e "${green} now generate empty img, it may take a while, wait please ... ${normal}"
sudo dd if=/dev/zero of=backup.img bs=1M count=$count status=progress

echo -e "${green} now part img ${normal}"
bootstart=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $2}'`
bootend=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $3}'`
rootstart=`sudo fdisk -l | grep $src_root_device_blkid | awk '{print $2}'`
echo "boot addr: $bootstart - $bootend, root addr: $rootstart >>> end"
sudo parted backup.img --script -- mklabel msdos
sudo parted backup.img --script -- mkpart primary fat32 ${bootstart}K ${bootend}K
sudo parted backup.img --script -- mkpart primary ext4 ${rootstart}K -1

echo -e "${green}mount loop device and copy files to image\n${normal}"
loopdevice=`sudo losetup --show -f backup.img`
echo $loopdevice
device=`sudo kpartx -va $loopdevice`
echo $device
device=`echo $device | sed -E 's/.*(loop[0-9]*)p.*/\1/g' | head -1`
# device=`echo $device |awk '{print $3}' | head -1`
echo $device
device="/dev/mapper/${device}"
boot_device="${device}p1"
root_device="${device}p2"
sleep 5
sudo mkfs.vfat $boot_device
sudo mkfs.ext4 $root_device
sudo mkdir -p /media/img_to_boot
sudo mkdir -p /media/img_to_root
sudo mkdir -p /media/img_src_boot
sudo mkdir -p /media/img_src_root
mount_path=`df -h|grep ${src_boot_device}|awk '{print $6}'`
if [ "x${mount_path}" == "x" ];then
  sudo mount -t vfat $src_boot_device /media/img_src_boot
  mount_path=/media/img_src_boot
fi
sudo mount -t vfat $boot_device /media/img_to_boot
echo -e "${green}copy /boot(${mount_path} to /media/img_to_boot)${normal}"
sudo cp -rf ${mount_path}/* /media/img_to_boot
sync


#################################

mount_path=`df -h|grep ${src_root_device}|awk '{print $6}'`
echo root mount path: $mount_path
if [ "x${mount_path}" == "x" ];then
  sudo mount -t ext4 $src_root_device /media/img_src_root
  mount_path=/media/img_src_root
fi
sudo mount -t ext4 $root_device /media/img_to_root

echo -e "${green}copy /${normal}"
if [[ "${copy_use_rsync}x" == "1x" ]]; then
  if [ "${backup_on_pi}x" == "1x" ]; then
    curr_dir=`pwd`
    backup_img_exclude="--exclude '${curr_dir}/backup.img'"
    backup_img_exclude=`echo ${backup_img_exclude} | sed -e "s/\///"`
  else
    backup_img_exclude=""
  fi
  if [ -f /etc/dphys-swapfile ]; then
    SWAPFILE=`cat /etc/dphys-swapfile | grep ^CONF_SWAPFILE | cut -f 2 -d=`
    if [ "$SWAPFILE" = "" ]; then
      SWAPFILE=/var/swap
    fi
    EXCLUDE_SWAPFILE="--exclude $SWAPFILE"
  fi
  sudo rsync --force -rltWDEgop --delete --stats --progress \
    $EXCLUDE_SWAPFILE \
    --exclude '.gvfs' \
    --exclude 'media/' \
    --exclude 'mnt/' \
    --exclude 'tmp/' \
    --exclude 'lost\+found/' \
    --exclude 'var/lib/apt/lists/' \
    $rsync_exlude \
    $backup_img_exclude \
    ${mount_path}/* /media/img_to_root
else
  if [ "${backup_on_pi}x" == "1x" ]; then
    # exclude backup.img from backup
    sudo chattr +d backup.img #exclude img file from backup(support in ext* file system)
  fi
  cd /media/img_to_root
  tmp_inode=`stat ${mount_path}/tmp --printf "%i"`
  lost_found_inode=`stat ${mount_path}/lost\+found/ --printf "%i"`
  media_inode=`stat ${mount_path}/media --printf "%i"`
  mnt_inode=`stat ${mount_path}/mnt --printf "%i"`
  apt_inode=`stat ${mount_path}/var/lib/apt/lists --printf "%i"`
  sudo dump -e ${tmp_inode},${lost_found_inode},${media_inode},${mnt_inode},${apt_inode} -0auf - ${mount_path} | sudo restore -rf -
fi

sync


echo -e "${green}update partUUID${normal}"
uuid_boot_src=`sudo blkid -o export ${src_boot_device_blkid} | grep PARTUUID`
uuid_boot_dst=`sudo blkid -o export ${boot_device} | grep PARTUUID`
uuid_root_src=`sudo blkid -o export ${src_root_device_blkid} | grep PARTUUID`
uuid_root_dst=`sudo blkid -o export ${root_device} | grep PARTUUID`
echo -e "${green}old boot partUUID: $uuid_boot_src , new: $uuid_boot_dst ${normal}"
echo -e "${green}old root partUUID: $uuid_root_src , new: $uuid_root_dst ${normal}"
sudo sed -i "s/$uuid_root_src/$uuid_root_dst/g" /media/img_to_boot/cmdline.txt
sudo sed -i "s/$uuid_root_src/$uuid_root_dst/g" /media/img_to_root/etc/fstab
sudo sed -i "s/$uuid_boot_src/$uuid_boot_dst/g" /media/img_to_root/etc/fstab
echo -e "${green}update partUUID complete${normal}"

# create temp dirs
sudo mkdir -p /media/img_to_root/tmp
sudo mkdir -p /media/img_to_root/media
sudo mkdir -p /media/img_to_root/mnt
sudo mkdir -p /media/img_to_root/tmp
sudo chmod 777 /media/img_to_root/tmp
sudo mkdir -p /media/img_to_root/var/lib/apt/lists

sync

sleep 5
cd
echo "loopdevice: $loopdevice"
echo -e "${green}umount /media/img_to_boot${normal}"
sudo umount /media/img_to_boot
echo -e "${green}umount /media/img_to_root${normal}"
sudo umount /media/img_to_root

sudo kpartx -d $loopdevice
sudo losetup -d $loopdevice
sudo rm /media/img_to_root /media/img_to_boot /media/img_src_root /media/img_src_boot -rf

if [ "${backup_on_pi}x" != "1x" ]; then
  echo -e "${green} umount ${normal}"
  sudo umount /media/backup_src_boot
  sudo umount /media/backup_src_root
  echo -e "${green} umount ok ${normal}"
fi

echo "====================="
echo -e "${green}\nbackup complete\n${normal}"
echo "====================="


3 运行脚本

​ 使用下面命令,查看虚拟机中磁盘剩余情况

df -h

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIIVe8GR-1652850933345)(assets/1641433055292.png)]

​ 可以看到,/dev/sda1还有27G的可用空间,我们的树莓派镜像实际大小应该在10G以内,虚拟机的空间是足够的,然后就把脚本拷贝到虚拟机中,准备运行

​ 把修改后的bachup_system.sh文件拷贝到家目录下,使用下面命令分配可执行权限

chmod 777 bachup_system.sh

​ 运行脚本

./bachup_system.sh

在这里插入图片描述

​ 输入yes,回车,等待。。。

在这里插入图片描述

在这里插入图片描述

​ 这个时候的镜像,就是压缩后的实际镜像了,看一下大小:

在这里插入图片描述

​ 真香。

4 镜像烧录

​ 镜像生成之后,可换一张SD卡,插入虚拟机后,先获得设备号

在这里插入图片描述

​ 然后使用下面命令进行烧录:

sudo dd if=backup.img of=/dev/sdb status=progress bs=1MiB

在这里插入图片描述

5 遇到的问题

5.1 boot地址错误

​ boot addr起始地址打印出来为*,如下图

在这里插入图片描述

​ 使用fdisk -l 查看SD卡实际分区情况

sudo fdisk -l

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbhBV5BC-1652850933354)(assets/1641454479698.png)]

​ 可以看到,实际的SD卡boot起始地址是2048-526335,但是脚本打印出来的起始地址确是*-2048,正好错了一位。

​ 查看脚本可以看到,脚本中获取起始地址的命令在这里:

bootstart=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $2}'`
bootend=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $3}'`
rootstart=`sudo fdisk -l | grep $src_root_device_blkid | awk '{print $2}'`

​ 直接在终端中输入下面命令获取起始地址:

sudo fdisk -l | grep /sdc1 | awk '{print $2}'

在这里插入图片描述

​ 打印出来的确是是*,把awk后的$2后移动一位,改为$3,脚本中获取地址的代码改为:

bootstart=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $3}'`
bootend=`sudo fdisk -l | grep $src_boot_device_blkid | awk '{print $4}'`
rootstart=`sudo fdisk -l | grep $src_root_device_blkid | awk '{print $2}'`

​ 而有的系统操作的时候不需要修改这里就能压缩成功,区别在哪里呢,我们找了一个无需修改的SD卡看一下他的分区情况

在这里插入图片描述

​ 可以发现,他的sd卡分区中,sdb1直接就是起始地址8192,没有那个*字符,直接原脚本中的命令去读取起始地址,返回的也是正确值,所以在没有修改脚本的情况下,他也生成成功了。

在这里插入图片描述

​ 至于为什么一个SD卡有 * ,一个没有 * ,留给后人研究吧。

5.2 提示找不到cmdline.txt

发现ubutu18.04的树莓派boot目录下,没有cmdline.txt这个文件,在config.txt中cmdline=nobtcmd.txt,以nobtcmd作为关键字,进行相应搜索,发现了下面的几个帖子

(50条消息) 树莓派 Ubuntu1804 安装k8s CGROUPS_MEMORY: missing 解决办法_nameLessor的博客-CSDN博客

​ 这个链接里,说ubuntu18.04的cmdline.txt改为了nobtcmd.txt

ubuntu树莓派4B+的GPIO硬件串口通信-pudn.com里也提到了4B刷ubuntu后用的是nobtcmd.txt这个文件

img 鉴于上述情况对脚本进行修改,把cmdLine.txt改为nobtcmd.txt

在这里插入图片描述

​ 这样就不再报cmdline.txt缺失的问题了,但是将备份好的镜像烧录到新的SD卡后,不进系统,报下面的错误:

Gave up waiting for suspend/resume device

Gave up waiting for root file system device.

-Boot args (cat /proc /cmdline)

    -Check rootdelay=(did the system wait long enough?)

-Missing modules( cat /proc /modules; ls /dev)

ALERT UUID=XXXXXXXXXXX does not exit. Dropping to a shell!

​ 搜索文件,跟cmdline.txt有关系

​ 参照这个大神的帖子,

教你树莓派4B的系统备份方法教程大全(全卡+压缩备份) - 走看看 (zoukankan.com)

​ 脚本中对nobtcmd.txt和对fstab的处理,是更新PARTUUID,将烧录好的SD卡插回linux虚拟机,使用blkid查看SD卡的UUID值,如下所示

在这里插入图片描述

​ 将UUID值分别写入nobtcmd.txt和fstab中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aokkYv7n-1658832324981)(C:\Users\CLX\Desktop\树莓派镜像压缩\assets\1658816145659.png)]

​ 改为:

PARTUUID=e0d8fe4b-02   /    ext4   defaults   0  0   
PARTUUID=e0d8fe4b-01   /    /boot/firmware    vfat   defaults   0  0   

​ 改了后,树莓派新的镜像可以进入图像化界面,但是输入用户名、密码无法登录。

5.2 使用dd烧录后SD卡空间变小了

在这里插入图片描述

​ 使用64G内存卡烧录压缩好的镜像,烧录完使用df-h发现64G的内存卡变成了8G,可以通过下面命令来恢复被“吃掉”的空间。

sudo parted /dev/mmcblk0 #使用parted来调整磁盘/dev/mmcblk0

​ 进入调整菜单,输入下面指令

print # 打印查看当前的分区情况
resizepart 2 -1 #将第2个分区充满剩下的空间
quit #退出

在这里插入图片描述

​ 此时在用df-h发现存储还是8G,接着输入下面指令

sudo resize2fs /dev/mmcblk0p2 #使用resize2fs来调整mmcblk0p2分区的大小 

在这里插入图片描述

​ 再用df-h看,内存就恢复了

5.3 copy /boot文件时报没有权限

在这里插入图片描述

​ 在脚本中找到报错的那一句

echo -e "${green}copy /boot(${mount_path} to /media/img_to_boot)${normal}"
sudo cp -rfp ${mount_path}/* /media/img_to_boot
sync

​ 在终端中单独发下面命令,报错相同

sudo cp -rfp /media/vr/E2A5-8E72/* /media/img_to_boot/

在这里插入图片描述

​ 指令跟了一个-p的后缀,查资料,-p是复制过程中保留权限、属主、时间戳的命令,试下把-p去掉,手动复制成功,所以,我们把脚本中的-p也给去除试一下,去除后,镜像生成成功。

echo -e "${green}copy /boot(${mount_path} to /media/img_to_boot)${normal}"
sudo cp -rf ${mount_path}/* /media/img_to_boot
sync

在这里插入图片描述

所以,我们把脚本中的-p也给去除试一下,去除后,镜像生成成功。

echo -e "${green}copy /boot(${mount_path} to /media/img_to_boot)${normal}"
sudo cp -rf ${mount_path}/* /media/img_to_boot
sync

在这里插入图片描述

5.4 DUMP过程中,报空间不足

	漫长的DUMP过到79%时,报空间不足,然后就停止打包,使用df -h命令查看空间使用情况

在这里插入图片描述
发现,脚本创建的loop0p2满了,在脚本里寻找这个空间创建相关的语句,发现下面语句中涉及到创建空间大小,并且该大小使用了一个变量root_back_size进行的设定

在这里插入图片描述
只管把这个变量设大,改为2,估摸着意思是把创建空间改为实际使用空间的2倍
在这里插入图片描述
改完后再运行脚本,bump过程中查看创建的空间大小
在这里插入图片描述
果然变大了很多,这次运行,直接到打包结束,没有再报空间不够的问题了。

6 ubunt18.04+ROS备份烧录-终极之战

​ 使用PiShrink 裁剪方式。

​ 通过裁剪用 Win32DiskImager 或者 dd 命令全卡备份的镜像,去掉没有内容的分区,从而减小备份镜像的大小。

​ 将全卡备份的镜像文件复制到 Linux 虚拟中,将pishrink.sh 脚本文件,存到镜像所在文件夹下。执行chmod +x pishrink.sh 增加执行权限,然后执行sudo bash pishrink.sh rpi-back.img 即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FF7kVqKm-1658832669751)(C:\Users\CLX\Desktop\树莓派镜像压缩\assets\1658823119171.png)]

​ 可以看到,镜像精简后,大小由原来的60G缩减为15G,使用Win32 磁盘映像工具将缩减后的镜像烧入一张新的SD卡,烧写完成后,上电,启动成功。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值