本文地址: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 支援的虛擬磁碟格式還有 VHDXHDD 等多種格式,詳細資訊請參考 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 虛擬空間的瘦身,這對於我們在某些場景下進行功能測試還是非常有幫助。

1.7 參考