在Ubuntu 18.04上使用zerofree

我在Windows 10专业版主机上使用VM VirtualBox来开发Ubuntu 18.04。之前,我按照这里的步骤压缩了虚拟硬盘: https://www.howtogeek.com/312883/how-to-shrink-a-virtualbox-virtual-machine-and-free-up-disk-space/ 除了常规更新外,我没有对它进行任何操作(最近只安装了VirtualBox增强功能的更新)。
以前,只有一个/dev/sda1显示出来,但今天我看到了三个,并且当我尝试在其中任何一个上运行zerofree时,提示设备已以读写方式挂载。

enter image description here

我也按照这里的一些指示尝试停止了一些服务并尝试重新挂载,但是没有成功。

https://unix.stackexchange.com/questions/42015/mount-is-busy-when-trying-to-mount-as-read-only-so-that-i-can-run-zerofree

它仍然显示挂载点忙

我不确定这是否是最近更新引起的? 我还试过卸载VMware客户机附加组件,但没有成功

有什么建议吗?


我不明白你在问什么,但是我只看到一个/dev/sda1,并没有看到三个。有一个/dev/sda1是你的根目录(或系统文件),一个/dev/sda2用于引导(或/boot/文件,内核和更有限的加密[如果使用]),还有一个/dev/sda3用于用户文件/home/ - 但对我来说,这是一个相当标准的设置,可以在安装时选择。无论如何,我没有看到三个/dev/sda1的提及。 - guiverc
https://askubuntu.com/a/1220639/5032 目前是最佳答案。 - endolith
为什么呢? - golimar
11个回答

以下是对我有效的方法(结合了几个相关问题和论坛的答案):
  • VirtualBox 5.2.10
  • Windows 10 作为主机操作系统
  • Ubuntu 18.04 作为客户操作系统

首先安装 zerofree:

sudo apt-get install zerofree

创建0字节文件以释放空间(删除所有不需要的文件并清空回收站)

重新启动到GRUB菜单(在Ubuntu启动时按Esc键)

Advanced options for Ubuntu > Recovery Mode (choose highest version number)

从“恢复菜单”中选择“切换到根shell提示符”
使用df命令获取分区信息(查看要缩小的分区,例如sda1、sda4等,通常为/dev/sda1)
df

尝试运行zerofree
zerofree /dev/sda1

分区是可读写的,需要以只读方式挂载才能运行zerofree错误:

如果您从zerofree收到像/dev/sda1被挂载为rw的错误,则需要将其以只读方式挂载才能继续。

要将/dev/sda1或您想要的分区以只读方式挂载以便使用zerofree

注意1:您应该相对快速地执行以下步骤,以便在服务和套接字重新开始使用并开始向磁盘写入之前将驱动器挂载为ro。否则,您可能需要再次执行systemctl步骤,以确保停止向磁盘写入。

注意2:(在以下步骤失败之前,请跳过阅读此内容)。根据您的系统,除了systemd-journald之外,您可能还有其他服务和套接字仍在向磁盘写入。如果下面的步骤不起作用,请尝试查看在运行这些步骤后仍在向磁盘写入的内容,然后以同样的方式停止它们

systemctl --type=service
systemctl --type=socket

步骤:

更新:用户@Kevin提出了一个很好的建议,即在服务和套接字重新启用时,可以使用一行命令来执行这些步骤(请参见下文):

systemctl stop systemd-journal* \
&& sudo swapoff -a && mount -n -o remount,ro -t ext2 /dev/sda1 / \
&& zerofree -v /dev/sda1

首先,停止所有正在向磁盘写入的进程,以免出现mount /: mount busy错误。

systemctl stop systemd-journald.socket
systemctl stop systemd-journald.service

检查是否启用了任何交换分区:
swapon -s

如果启用了,那就禁用它们。
sudo swapoff -a

最后,你应该能够将dev/sda1挂载为只读模式。(你的文件系统类型可能与ext2不同。要找到文件系统,请运行df -T
mount -n -o remount,ro -t ext2 /dev/sda1 /

最后运行zerofree
zerofree -v /dev/sda1

zerofree 完成后,关闭 Ubuntu。
halt

最后,在主机操作系统上(在我这里是Windows 10),压缩vdi以回收空间。
VBoxManage.exe modifymedium disk "C:\path\to\disk.vdi" --compact

很棒的建议:systemctl stop + swapoff。它们是我解决问题的关键。 - Marvin
1在执行挂载命令后,我一直收到“mount: / is busy”的错误提示。根据这个问题的另一个回答中提到的方法,停止其他服务解决了这个问题(https://unix.stackexchange.com/questions/42015/mount-is-busy-when-trying-to-mount-as-read-only-so-that-i-can-run-zerofree)(`service rsyslog stop && killall dhclient`)。 - chiliNUT
嗨埃曼纽尔,你的解决方案中最后一步"modifymedium"在我的情况下从来没有运行过,而且停留在0%上永远不动。我不知道为什么!是什么原因呢? - Ash
@Ash 可能是一个bug.. 你使用的VirtualBox版本是多少?试试使用一个不同(更新)的VirtualBox版本(早期版本的VB例如使用modifyhdmodifyvdi而不是modifymedium)。 - Emmanuel N K
奇怪的是,第二次尝试时居然成功了:) - Ash
但是,更难做的事情实际上是调整我的.vdi文件的大小,因为它的虚拟尺寸非常大。无论是VB还是Windows都没有这样的能力,也不允许使用modifymedium --resize命令来修改大小。 - Ash
killall dhclient 对我来说起到了作用。 - panta82
3我在Ubuntu 20.04 LTS上执行了以下操作:systemctl stop systemd-journal* && swapon -s && sudo swapoff -a && mount -n -o remount,ro -t ext4 /dev/sda<your number> /... 我只使用了一个停止命令,它有效果:systemctl stop systemd-journal*... - ofarouk

安装 zerofree

sudo apt install zerofree

重启进入 Ubuntu 恢复控制台,按住 [右 SHIFT] 键

高级选项 -> 恢复模式 -> root 控制台

找到根目录

mount | grep "sda"

运行 zerofree

echo "u" > /proc/sysrq-trigger
mount /dev/mapper / -o remount,ro
zerofree -v /dev/sda1

重新启动
关机 -r 现在
压缩驱动器
VBoxManage modifyhd /path/to/VDI/VM.vdi --compact
来源:来自ubuntuforums.org的cyplex

2在我的情况下,执行echo "u" > /proc/sysrq-trigger似乎起到了作用。其他我阅读到的停止各种服务、杀死dhclients、禁用交换空间的建议都不够有效。 - vlad_tepesch
2这个实际上可以在20.04版本中使用。 - dawnslayer
1这个实际上可以在21.04版本中使用。 - endolith

我使用了Emmanuels的解决方案,只有在关闭另外两个套接字之后才起作用。
systemctl stop systemd-journald.socket 

新的行:

systemctl stop systemd-journald-dev-log.socket
systemctl stop systemd-journald-audit.socket

systemctl stop systemd-journald.service
sudo swapoff -a 
mount -n -o remount,ro -t ext4 /dev/sda1 / 
zerofree /dev/sda1

注意:我使用的是Ubuntu 18.04.3和EXT4文件系统。
将我的磁盘从40GB缩小到7GB。谢谢。 :)

我曾经安装并运行了'haveged',因为我们曾经遇到过熵问题,不得不停止该服务。除了这四个systemctl停止命令之外,我还添加了额外的一行systemctl stop haveged.service。这样做对我来说解决了问题。 - Mahn
1成功了!非常感谢,你的解决方案让我免去了5个小时的煎熬。 - Benjamin
从上面的解决方案中,对我起作用了。非常感谢! - Jack

如评论中提到的,您有三个已挂载的分区(sda1、sda2和sda3),以及用于其他目的的几个临时文件系统。
《zerofree》的手册指出,如果要在文件系统上运行此程序,则该文件系统必须是只读挂载或未挂载。当您运行Ubuntu时,可以确定根分区“/”(在您的计算机上为“/dev/sda1”)已挂载,因此该命令将失败。
如果您想在“/dev/sda1”上运行《zerofree》,您需要从备用设备引导,例如可启动的USB或ISO映像,或者执行chroot到备用Linux映像。您引用的链接中有关于如何在根分区上运行此程序的具体说明。请重新阅读他们关于如何在Linux中使用此程序的说明。
  • 在操作系统加载之前启动并访问Grub
  • 从grub菜单中选择“高级选项”
  • 进入恢复模式会话
  • 使用“root”登录
  • 识别磁盘
  • 运行zerofree
  • 停止机器
  • 关闭电源并重新启动虚拟机

2019年1月22日

当前版本的Ubuntu在恢复模式下运行zerofree变得困难 - 在这种情况下,更容易从一个活动的USB设备上运行此程序:

  • 下载最新的Ubuntu iso文件
  • 使用Ubuntu iso创建一个活动的USB / CD
  • 从活动媒体启动您的设备(这也可以在虚拟机中完成)
  • 如果尚未安装,请使用命令sudo apt install zerofree安装程序zerofree
  • 运行命令
  • 重新启动机器

2这就是我所做的,从GRUB选择根目录, 当我尝试在/dev/sda1上运行zerofree时 - 它说它已经以读写方式挂载了。 - Danish
有没有办法在GRUB中以root身份重新将/dev/sda1挂载为只读?我已经尝试过使用mount -n -o remount,ro -t ext2 /dev/sda1 /命令,但返回的信息是/mount is busy。实际上,我之前已经做过3-4次这样的操作,而且都成功了。这一次却显示/dev/sda1以读写模式挂载,不确定是什么改变了,是更新导致的吗? - Danish
1如果是我,我会从像Ubuntu安装盘这样的ISO文件启动,并选择“试用Ubuntu”。然后,由于我正在运行来自非正常磁盘的系统,我可以安装zerofree并在磁盘的分区上运行它。 - Charles Green
问题是,你有没有想法如何在外部运行引导ISO?我的Ubuntu是在虚拟机中的 :;/ - Danish
2在VirtualBox中有一个选项,可以将ISO文件挂载为CD,然后从该CD启动。其中一些链接可能比较旧,但是操作步骤非常相似。https://forums.virtualbox.org/viewtopic.php?t=55617 或者 https://www.dedoimedo.com/computers/virtualbox-cdrom.html 或者 https://www.howtogeek.com/187721/how-to-boot-from-a-usb-drive-in-virtualbox/ - Charles Green
你描述的恢复会话过程不起作用。显然,默认情况下,恢复会话会将根文件系统挂载为读写模式。 - Giacomo Alzetta
2@GiacomoAlzetta 我的理解是,在Ubuntu 18.10发布后,恢复会话的行为有所改变 - 许多人报告说他们无法在恢复模式下运行fsck来检查'/'。因此,我们被迫使用Live USB或CD来代替这个操作,就像我之前提到的那样,大约三条评论之前... - Charles Green
我使用的是18.04版本,所以变化肯定比18.10早。 - Giacomo Alzetta
@GiacomoAlzetta 在那其中的某个地方,你仍然会找到很多回答说:“引导到恢复模式并运行fsck……” - Charles Green
@GiacomoAlzetta 就我个人而言,我总是在某个地方备有一个活动的USB... - Charles Green
可以确认查尔斯所说的。我正在使用Ubuntu Server 20.04,不得不使用安装ISO引导我的虚拟机,然后进入shell(在安装菜单上选择选项),然后我才能在我想要的设备上使用zerofree命令。在此之前,由于读写挂载的原因,这是不可能的。 - João Ciocca
@JoãoCiocca 你是怎么安装这个设备的?(在执行zerofree命令之前) - Rogelio Prieto

我想对Charles Green的回答添加评论,但是我声望不够。
当运行zerofree命令时,你可能会遇到一个错误,提示/dev/sda1分区已挂载为读写。在这种情况下,你需要将该分区重新挂载为只读:
mount -n -o remount,ro -t ext2 /dev/sda1 /

重新运行zerofree命令,如此处所述。

我使用了Emmanuel的解决方案,它起作用了。但是对于我来说,服务和套接字回退得太快了,就像他提到的那样,所以在失败了几次之后,我决定使用链式命令在一行中完成所有步骤。
systemctl stop systemd-journald.socket && systemctl stop systemd-journald.service && sudo swapoff -a && mount -n -o remount,ro -t ext2 /dev/sda1 / && zerofree /dev/sda1

终于成功了。


这是我在Ubuntu 18.04服务器客户机上的操作步骤:
  1. Ubuntu 18.04 桌面版 Live CD 放入虚拟机的光驱中(确保启动顺序首先加载此光盘)
  2. 启动虚拟机,当光盘询问时:点击 尝试 Ubuntu
  3. 一旦图形界面启动,打开终端
  4. sudo apt install zerofree 并等待安装完成
  5. sudo fdisk -l 并记录系统硬盘,例如 /dev/sda2
  6. sudo zerofree -v /dev/sda2 并等待操作完成
  7. halt
  8. 使用 ACPI 关闭虚拟机
  9. 在重新启动之前,从虚拟机的光驱中取出 Ubuntu 18.04 桌面版 Live CD

我成功地通过使用dd而不是zerofree来缩小了VBox虚拟机映像的大小。

  1. 正常登录Ubuntu(我的虚拟机是elementary OS 5.1)
  2. 运行sudo dd if=/dev/zero of=/EMPTY bs=1M
  3. 运行sudo rm -f /EMPTY
  4. 关机:sudo poweroff
  5. 主机操作系统(Windows 10)中运行VBoxManage.exe modifyhd vbox.vdi --compact

我的虚拟机文件从8GB缩小到6GB。 注意:可以忽略一些警告输出。

以下是我输入/输出的完整示例:

在虚拟机中:

erich@vbox:~$ sudo dd if=/dev/zero of=/EMPTY bs=1M status=progress
[sudo] password for erich:         
97889812480 bytes (98 GB, 91 GiB) copied, 415 s, 236 MB/s
dd: error writing '/EMPTY': No space left on device
93399+0 records in
93398+0 records out
97934905344 bytes (98 GB, 91 GiB) copied, 415.592 s, 236 MB/s
erich@vbox:~$ sudo rm -f /EMPTY
bash: cannot create temp file for here-document: No space left on device

在主机操作系统中:
cd <C:/path/to/folder/of/vbox.vdi>
"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" modifyhd eOS.vdi --compact
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

这个方法是可行的,但人们更愿意使用zerofree而不是在虚拟机上使用dd有其原因:dd会将整个驱动器填满到最大容量,而zerofree只会清零“未使用的扇区”。所以,如果你有一个2TB的虚拟镜像,只使用了其中的2GB,并且想要回收100MB的空间,dd会将镜像扩展到2TB,而zerofill只会清零100MB而不改变镜像大小。在某些情况下,这会产生巨大的影响,比如当主机上的可用空间小于磁盘可能增长到的最大尺寸时。 - msanford

只需使用来自此开源项目的Live CD,在Linux主机/客户端上(该Live CD内置了zerofree实用程序;还请阅读该网站上的说明):

https://sourceforge.net/projects/live-cd-with-zerofree-utility/

这也有助于减小导出的虚拟机设备的大小(即.ova文件)。
正如其他人所提到的,在运行zerofree之后,使用紧凑选项来减小vdi文件的大小。
附注:此Live CD还提供了32位版本(i686架构),可在以下链接下载:https://sourceforge.net/projects/live-cd-with-zerofree-32-bit/

我正在使用通过phpvirtualbox远程访问的Ubuntu 18.04服务器虚拟机。似乎有很多服务在运行。
我尝试了上面提到的各种提示,但是Teoman引用的方法是我唯一能够将驱动器挂载为只读,并且能够运行zerofree的方式。
(顺便说一句,如果您的虚拟机已加密,则没有必要这样做,因为在加密时无法压缩虚拟机。我的虚拟机是加密的。)