本文地址:https://www.ebpf.top/post/shrink_vbox_vmdk_size
在使用 VirtualBox( VMDK 模式)管理虛擬機的時候,我們經常會遇到一些編譯安裝場景(比如編譯 Linux 內核),會導致磁盤空間急劇膨脹,但是在編譯完成后即使我們刪除了相關的文件,在 VM 虛擬機占用主機的空間卻並沒有減少,這時候為了騰出磁盤空間或者更方便與他人分享,我們需要給 VM 的磁盤進行瘦身操作。
1.1 虛擬磁盤格式介紹
VirtualBox 主要支持下列虛擬磁盤格式為 VMDK 和 VDI:
- VMDK(Virtual Machine Disk) 最初是由 VMware 為其產品研發的格式。該格式技術設計文檔最初是閉源的,而現在已經開源,在 VirtualBox 里完全可用。這種格式有個功能是:把一個虛擬機的鏡像分割成多個 2GB 大小的文件。如果你要把虛擬機鏡像放在不支持大文件的文件系統(例如 FAT32)上,那么這個功能就非常有用。在其他的虛擬磁盤格式里,能做到同樣功能的只有 Parallels 的 HDD。
- VDI(Virtual Disk Image) 格式是 VirtualBox 新建虛擬機時默認選用的格式。也是 VirtualBox 的自有開放格式。
VirtualBox 支持的虛擬磁盤格式還有 VHDX 和 HDD 等多種格式,詳細信息請參考 VirtualBox 簡體中文 。
1.2 用零字節填充空閑空間
VirtualBox 只有在空間被設置為零的情況下才知道這是磁盤中真正的空閑空間,這與我們在一般機器上通過標准的 rm 命令刪除即可釋放空間有很大不同。
為了實現這個效果,我們需要登錄到 VM 主機中登錄到虛擬機中,使用零字節空間填充掉空閑空間,然后再把填充的文件進行刪除,即可達到效果。
$ cat /dev/zero > zero.fill; sync; sleep 1; sync; rm -f zero.fill
cat: write error: No space left on device
在命令執行完成后,會出先一個 “cat: write error: No space left on device” 的錯誤,這個錯誤恰恰表明我們使用零字節填充了所有的空閑空間。
至此,我們已經在 VM 虛擬機中成功地將空閑的空間進行了零字節填充,是時候進行真正的 “ 減肥 ” 操作了。
1.3 定位 VM 虛擬磁盤文件
在 VirtualBox 運行的主界面上,我們可以通過在虛擬機上點擊右鍵,在彈出的菜單上選擇 “Setting“ 選項,會彈出本虛擬相關的設置,切換到 ”Storage“ 選項卡。
圖 1-1 進入 VM 的設置頁面
在 ”Storage“ 選項卡的主界面中我們可以看到 VM 掛載的虛擬磁盤,點擊虛擬磁盤選項,在右側的 ”Attributes“ 信息欄中就可以在 ”Location“ 項中查詢到選擇虛擬磁盤所在的目錄和文件名。
目錄默認保存位置為 ~/VirtualBox VMs/ 目錄下以 VM 名稱命名的子目錄下,如本例中的 ~/VirtualBox VMs/ubuntu_21_04_default_1632463892989_42055,其中 ubuntu_21_04_default_1632463892989_42055
為 VM 主機名。
圖 1-2 進入 VM 的設置頁面中的存儲項詳情
確定 VM 的虛擬磁盤所在目錄后,我們通過終端進入到對應的目錄,進行查看:
$ cd ~/VirtualBox\ VMs/ubuntu_21_04_default_1632463892989_42055/
$ ls -lh
-rw------- 1 dwh0403 staff 35G Sep 28 13:37 ubuntu-hirsute-21.04-cloudimg.vmdk
...
這里我們可以看到該該虛擬磁盤占用了 35G 的磁盤大小。我們可以通過 vboxmanage showhdinfo
命令查看 vmdk 文件的詳情(如果后續需要繼續使用 vmdk 格式需要):
$ vboxmanage showhdinfo ubuntu-hirsute-21.04-cloudimg.vmdk
UUID: 6a00f1e1-a53f-4a48-9f41-4f2a96248286
Parent UUID: base
State: created
Type: normal (base)
Location: /Users/dwh0403/VirtualBox VMs/ubuntu_21_04_default_1632463892989_42055/ubuntu-hirsute-21.04-cloudimg.vmdk
Storage format: VMDK
Format variant: dynamic default
Capacity: 40960 MBytes
Size on disk: 35717 MBytes
Encryption: disabled
為了壓縮虛擬磁盤的空間,我們需要將 vmdk 格式轉換成 vdi 格式。如果本機安裝了 Vmware 產品,可以直接使用其提供的工具直接進行瘦身,參見 Vmware 磁盤管理樣例 。
$ vboxmanage clonehd --format vdi ubuntu-hirsute-21.04-cloudimg.vmdk ubuntu-hirsute-21.04-cloudimg.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone medium created in format 'vdi'. UUID: 46de9fce-0055-472b-aee2-128509e3685
$ ls -hl
-rw------- 1 dwh0403 staff 11G Sep 28 13:41 ubuntu-hirsute-21.04-cloudimg.vdi
...
$ vboxmanage modifyhd ubuntu-hirsute-21.04-cloudimg.vdi --compact
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
待轉換完成后,我們可以在當前目錄進行查看可以發現 vdi 的文件大小已經降低至 11G(原始 vmdk 文件為 35G 大小),表明在轉換過程中已經完成了磁盤空間的縮容。
1.4 將 VDI 格式的磁盤掛載(方案一,驗證,推薦)
在轉換 vdi 格式后,已經完成了空間的調整,如果我們並去強烈使用 vmdk 格式,我們可以直接將原來的 vmdk 格式虛擬磁盤從 VM 中卸載,然后將 vdi 格式的磁盤掛載即可。同時記得刪除 vmdk 格式的虛擬磁盤。
在保持 VM 虛擬機關閉的情況下,進入到 VM 的存儲設置頁面,步驟與圖 1-2 一致。
首先,在移除老的 vmdk 格式的虛擬磁盤上點擊右鍵,在右鍵菜單屬性中選擇 ”Remove Attachment“:
然后鼠標選擇磁盤控制器,選擇添加磁盤按鈕:
在彈出的添加磁盤文件的窗口中選擇 ”Add“ 按鈕,進入到選擇文件窗口,選擇我們新的 vdi 格式文件即可。
然后將 VM 虛擬機啟動驗證,如果一切順利則完成了整個瘦身過程。
這里推薦使用 vdi 格式的虛擬磁盤格式,后續在磁盤空間吃緊的情況還可以使用下述命令調整大小:
$ VBoxManage modifyhd xxx.vdi --resize the_new_size
1.5 使用 VMDK 格式的磁盤掛載(方案二,未驗證)
如果由於特殊原因必須使用 vmdk 格式的虛擬磁盤,我們需要將瘦身后的 vdi 格式文件重新轉換為 vmdk 格式:
$ VBoxManage clonehd ubuntu-hirsute-21.04-cloudimg.vdi ubuntu-hirsute-21.04-cloudimg_new.vmdk --format vmdk
這里可以選擇如上述方案相同的方式,通過去除虛擬磁盤再添加新的磁盤,如果使用原有的文件名字覆蓋的話,由於轉換過程中生成了新的 UUID,則會導致 VirtualBox 不能夠識別新的虛擬磁盤,這里需要重新設置 UUID。
$ vboxmanage internalcommands sethduuid ./ubuntu-hirsute-21.04-cloudimg <原 UUID 在此>
1.5.1 錯誤解決:
$ VBoxManage clonehd ubuntu_21_04_default_1632463892989_42055/ubuntu-hirsute-21.04-cloudimg.vdi ubuntu-hirsute-21.04-cloudimg.vmdk --format vmdk
VBoxManage: error: UUID {6438d068-ae7b-467d-ab30-6e1228c30bd9} of the medium '/Users/dwh0403/VirtualBox VMs/ubuntu_21_04_default_1632463892989_42055/ubuntu-hirsute-21.04-cloudimg.vdi' does not match the value {46de9fce-0055-472b-aee2-128509e3685d} stored in the media registry ('/Users/dwh0403/Library/VirtualBox/VirtualBox.xml')
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MediumWrap, interface IMedium, callee nsISupports
VBoxManage: error: Context: "CloneTo(pDstMedium, ComSafeArrayAsInParam(l_variants), NULL, pProgress.asOutParam())" at line 1068 of file VBoxManageDisk.cpp
如果有上述報錯,建議修改 vmdk 生成的文件名重試。
1.6 總結
最后,我們可以已經成功完成了 VM 虛擬空間的瘦身,這對於我們在某些場景下進行功能測試還是非常有幫助。