Shrink guest on hosted platform: Difference between revisions
(25 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
== Important == | |||
Note that the technique described below to zero out the unused space on the guest OS will in fact make your guest virtual disk grow to the maximum size first. For each byte that is changed to zero the virtual disk will need to claim a byte. This means that while you can use the technique to reclaim disk space after the unused space is zero'd out, it is important to have enough space before you start. | Note that the technique described below to zero out the unused space on the guest OS will in fact make your guest virtual disk grow to the maximum size first. For each byte that is changed to zero the virtual disk will need to claim a byte. This means that while you can use the technique to reclaim disk space after the unused space is zero'd out, it is important to have enough space before you start. | ||
If you don't have that kind of free disk space then you can skip the zero-ing out part. You can still reclaim space, but it will be less optimal. | |||
Alternatively you can use the "Partially zero out" trick described below. | |||
Before we try to shrink the virtual disk files, we should try to remove any unneeded files from the virtual machine to free space. | === How much free space do you need before shrinking? === | ||
Also please note that you need more free space in order to be able to run the shrinking process. | |||
The shrinking process consists of making a copy of your virtual disk while omitting the zero'd out blocks. | |||
So how much extra space you need depends on how you configured the virtual disk for your Virtual Machine. | |||
If your Virtual Disk is a single file, then your free space requirement can grow up-to the full size of that virtual disk. | |||
If OTOH you are using the split disk scheme where a virtual disk is sliced into multiple files the maximum free space you need is the maximum size a slice can be. Nowadays there's not a fixed slice size, it depends on how big your virtual disk actually is. | |||
The split disk scheme since VMware Workstation 11 (VMware Fusion 7), older version of Workstation/Fusion use a 2GB split disk scheme. | |||
Capacity Extent size | |||
================================ | |||
<=128GB 4GB (increased from 2GB) | |||
>128GB && <2TB Capacity / 32 (so maximum of 32 extents) | |||
>=2TB 2TB | |||
For extra safety I recommend to make sure you have an additional 2GB of free space on top of those requirements as mentioned above. | |||
As side note, this also explains why it is generally recommended at the forum by the regulars to use a split disk scheme over single disk files. | |||
This same problem also exists when you want to commit snapshots. | |||
=== Using the clean up option in the menu === | |||
When you use the "Clean Up Disks" option in the menu in VMware Workstation 12 or later, then you do not require extra disk space for reclaiming space (see also: [https://docs.vmware.com/en/VMware-Workstation-Pro/14.0/com.vmware.ws.using.doc/GUID-421A1073-BF16-4BC7-AA76-46B954CA438D.html Clean Up a Virtual Hard Disk on Windows Hosts] ) | |||
Currently this only works for Windows guests where the filesystem is NTFS. | |||
== Zero out unused space in a Linux VM == | |||
Before we try to shrink the virtual disk files, we should try to remove any unneeded files from the virtual machine to free space. | |||
More free space means more disk space that can get reclaimed. | |||
One of the areas in a VM that can take up a lot of disk space is the repository cache. So I personally tend to clean the cache in the VM before reclaiming disk space at the host. | |||
Clean up your repositories: | Clean up your repositories: | ||
For example, on Debian-based VMs, you can run | For example, on Debian-based VMs, you can run the following command (in the VM) | ||
apt-get clean all | apt-get clean all | ||
Line 17: | Line 52: | ||
yum clean | yum clean | ||
The next step is important: | |||
Shut down any services that depend on having enough available disk space to run. | |||
The reason for this is that we are going to write out zero's to the file system until the file system is full and we do not want any application - for example a database system like mySQL or postgreSQL - to run out of disk space while we are zeroing out the file system. If mySQL would try to write when your disk is full you risk a corrupted database. So this step is important! | The reason for this is that we are going to write out zero's to the file system until the file system is full and we do not want any application - for example a database system like mySQL or postgreSQL - to run out of disk space while we are zeroing out the file system. If mySQL would try to write when your disk is full you risk a corrupted database. So this step is important! | ||
Next run: | Next run (also from within the VM): | ||
cat /dev/zero > zero.fill;sync;sleep 1;sync;rm -f zero.fill | cat /dev/zero > zero.fill;sync;sleep 1;sync;rm -f zero.fill | ||
Line 34: | Line 71: | ||
cat /dev/zero > /home/zero.fill;sync;sleep 1;sync;rm -f /home/zero.fill | cat /dev/zero > /home/zero.fill;sync;sleep 1;sync;rm -f /home/zero.fill | ||
==== Zero out unused space on a Windows VM | === Zero out a part of your virtual disk === | ||
If your virtual machine cannot be taken down and you do not want to shut down services that might end up corrupting files because of the "No space left on the device" problem then an idea that might work is to zero out a part of your partition. | |||
This for example creates a 100MB size file filled with zero's | |||
# dd if=/dev/zero of=zero.fill bs=1024 count=102400 | |||
102400+0 records in | |||
102400+0 records out | |||
104857600 bytes (105 MB) copied, 0.3839 s, 273 MB/s | |||
So if you want to zero out 10GB instead, add two more zero's to the count parameter, eg: count=10240000 | |||
If you want to fill up in steps, just change the output file name from "zero.fill" into "zero.fill2" etcetera.. | |||
Then run the "sync; sleep 1; sync" from above and remove the zero.fill files. | |||
If your VM is running on VMware vSphere and you have a NFS LUN with enough free space then one way to reclaim your space is to Storage vMotion the VM to NFS storage and back. Once done the zero'd out data has been reclaimed. No need to shut down the VM. | |||
If this is not for you, then do read on. | |||
=== Zero out using fstrim === | |||
These days there's an alternative way for zero-ing out the parts of the disk that are not used using [https://www.man7.org/linux/man-pages/man8/fstrim.8.html fstrim]. | |||
eg: | |||
# fstrim -a -v | |||
/var: 274.3 MiB (287592448 bytes) trimmed on /dev/sda3 | |||
/tmp: 63 MiB (66060288 bytes) trimmed on /dev/sda5 | |||
/home: 125 MiB (131072000 bytes) trimmed on /dev/sda6 | |||
/boot/efi: 505.2 MiB (529735680 bytes) trimmed on /dev/sda1 | |||
/: 5 MiB (5242880 bytes) trimmed on /dev/sda2 | |||
The great thing about this is that it only zero's out the parts of the disk that are not zero and as such the disk does not inflate to its full size. | |||
* [https://forums.freebsd.org/threads/ssd-trim-maintenance.56951/post-328912 Detail comment from Theodore Ts'o on using fstrim] | |||
* [https://github.com/vmware/open-vm-tools/issues/457 Avoid disk expansion while shrinking (github issue tracker)] | |||
On most modern systems fstrim is being run automatically using systemctl. You can check if it is enabled: | |||
# systemctl status fstrim.timer | |||
● fstrim.timer - Discard unused blocks once a week | |||
Loaded: loaded (/lib/systemd/system/fstrim.timer; disabled; vendor preset: enabled) | |||
Active: inactive (dead) | |||
Trigger: n/a | |||
Triggers: ● fstrim.service | |||
Docs: man:fstrim | |||
Oh-huh, our system does not have it enabled.. might there be a reason, such as that the UNMAP command is not supported? | |||
If so, the following command would return 0. | |||
# cat /sys/block/sda/queue/discard_max_bytes | |||
1073741824 | |||
So UNMAP is supported, but fstrim still is not enabled, lets fix that. | |||
# systemctl enable fstrim.timer | |||
Created symlink /etc/systemd/system/timers.target.wants/fstrim.timer → /lib/systemd/system/fstrim.timer. | |||
and reload systemctl plus check that it now works... | |||
# systemctl start fstrim.timer | |||
# systemctl daemon-reload | |||
# systemctl status fstrim.timer | |||
● fstrim.timer - Discard unused blocks once a week | |||
Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled) | |||
Active: active (waiting) since Sat 2024-01-06 13:00:46 CET; 6s ago | |||
Trigger: Mon 2024-01-08 01:17:59 CET; 1 day 12h left | |||
Triggers: ● fstrim.service | |||
Docs: man:fstrim | |||
see also: | |||
* https://www.suse.com/support/kb/doc/?id=000019447 | |||
== Zero out unused space on a Windows VM == | |||
To do the same with a windows VM, you can use Microsoft's tool [http://technet.microsoft.com/en-us/sysinternals/bb897443.aspx sdelete]. | To do the same with a windows VM, you can use Microsoft's tool [http://technet.microsoft.com/en-us/sysinternals/bb897443.aspx sdelete]. | ||
Line 49: | Line 159: | ||
The trigger to zero space with 0x00 has changed to -z! | The trigger to zero space with 0x00 has changed to -z! | ||
=== Shrink the disk | == Zeroing an encrypted disk == | ||
If you use disk encryption in the guest OS then zero'ing out the disk won't help. | |||
The reason is that a good disk encryption scheme will write out random data to the disk when you write out zero's. | |||
In other words, if you have enabled full disk encryption in the guest then you can not shrink the disk anymore as there is no space to reclaim. | |||
== Shrink the disk == | |||
Then power down the VM and open a terminal on the Linux host. | Then power down the VM and open a terminal on the Linux host. | ||
Line 65: | Line 183: | ||
Note that vmware-vdiskmanager is probably not in your search path, so you might have to prepend the vmware-vdiskmanager command with the actual path with the command is located. | Note that vmware-vdiskmanager is probably not in your search path, so you might have to prepend the vmware-vdiskmanager command with the actual path with the command is located. | ||
On macOS you run it as: | |||
/Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -k Ubuntu\ Desktop.vmdk | |||
If you need to use "sudo" in order to be able to run the above then beware that the ownership of the .vmdk files might get changed to root. So certainly try it first without running as root! | |||
You will have to change the ownership back to your own user, eg: | |||
sudo chown username: *.vmdk | |||
If you don't change the ownership back you might see errors like: | |||
"Unable to open file .../Virtual Disk.vmdk: Insufficient permission to access file". | |||
== Shrink using vmware tools == | |||
Nowadays you can also shrink the guest by using the shrink feature as offered via vmware tools. | Nowadays you can also shrink the guest by using the shrink feature as offered via vmware tools. | ||
So for clarity all of the following commands are run from within the guest to shrink the disk while the guest is running. | |||
On linux in order to use this run: | On linux in order to use this run: | ||
Line 74: | Line 204: | ||
Where "/" is the mount point of the partition that you want to shrink. | Where "/" is the mount point of the partition that you want to shrink. | ||
On Windows in order to use this run: | On Windows in order to use this run (as administrator): | ||
C:\Program Files\VMware\VMware Tools>VMwareToolboxCmd.exe disk shrink <location> | C:\Program Files\VMware\VMware Tools>VMwareToolboxCmd.exe disk shrink <location> | ||
where <location> is the drive you want to shrink | where <location> is the drive you want to shrink | ||
For example: | |||
C:\Program Files\VMware\VMware Tools>VMwareToolboxCmd.exe disk shrink c:\ | |||
Please disregard any warnings about disk space for the duration of shrink process. | |||
Progress: 62 [=======> ] | |||
The progress you see here is VMware Tools blanking out the unused space. | |||
At 99% it will popup the "Shrinking Disk" progress dialog at the host that takes care of the actual shrinking process. | |||
If you are logged in via remote desktop then do expect to loose the connection for a bit while the actual shrinking is taking place. | |||
On OS X / macOS the command to use is: | On OS X / macOS the command to use is: | ||
sudo /Library/Application\ Support/VMware\ Tools/vmware-tools-cli disk shrink / | sudo /Library/Application\ Support/VMware\ Tools/vmware-tools-cli disk shrink / | ||
== Shrink macOS VM with APFS == | |||
[https://communities.vmware.com/thread/581576 Solved: Shrink an APFS virtual disk] | |||
== External links == | |||
* [https://docs.vmware.com/en/VMware-Workstation-Pro/16.0/com.vmware.ws.using.doc/GUID-421A1073-BF16-4BC7-AA76-46B954CA438D.html Clean Up a Virtual Hard Disk on Windows Hosts - Workstation 16 Pro documentation] | |||
* [https://docs.vmware.com/en/VMware-Workstation-Pro/16.0/com.vmware.ws.using.doc/GUID-3F94C7B5-19A5-4E91-9709-B17FAA93FF75.html Configuring and Maintaining Virtual Hard Disks - Workstation 16 Pro documentation] | |||
* [https://docs.vmware.com/en/VMware-Fusion/12/com.vmware.fusion.using.doc/GUID-6BB29187-F47F-41D1-AD92-1754036DACD9.html#GUID-6BB29187-F47F-41D1-AD92-1754036DACD9 Clean up a Virtual Machine - VMware Fusion 12 documentation] |
Latest revision as of 13:02, 6 January 2024
Important
Note that the technique described below to zero out the unused space on the guest OS will in fact make your guest virtual disk grow to the maximum size first. For each byte that is changed to zero the virtual disk will need to claim a byte. This means that while you can use the technique to reclaim disk space after the unused space is zero'd out, it is important to have enough space before you start.
If you don't have that kind of free disk space then you can skip the zero-ing out part. You can still reclaim space, but it will be less optimal. Alternatively you can use the "Partially zero out" trick described below.
How much free space do you need before shrinking?
Also please note that you need more free space in order to be able to run the shrinking process. The shrinking process consists of making a copy of your virtual disk while omitting the zero'd out blocks. So how much extra space you need depends on how you configured the virtual disk for your Virtual Machine. If your Virtual Disk is a single file, then your free space requirement can grow up-to the full size of that virtual disk.
If OTOH you are using the split disk scheme where a virtual disk is sliced into multiple files the maximum free space you need is the maximum size a slice can be. Nowadays there's not a fixed slice size, it depends on how big your virtual disk actually is.
The split disk scheme since VMware Workstation 11 (VMware Fusion 7), older version of Workstation/Fusion use a 2GB split disk scheme.
Capacity Extent size ================================ <=128GB 4GB (increased from 2GB) >128GB && <2TB Capacity / 32 (so maximum of 32 extents) >=2TB 2TB
For extra safety I recommend to make sure you have an additional 2GB of free space on top of those requirements as mentioned above.
As side note, this also explains why it is generally recommended at the forum by the regulars to use a split disk scheme over single disk files. This same problem also exists when you want to commit snapshots.
When you use the "Clean Up Disks" option in the menu in VMware Workstation 12 or later, then you do not require extra disk space for reclaiming space (see also: Clean Up a Virtual Hard Disk on Windows Hosts )
Currently this only works for Windows guests where the filesystem is NTFS.
Zero out unused space in a Linux VM
Before we try to shrink the virtual disk files, we should try to remove any unneeded files from the virtual machine to free space. More free space means more disk space that can get reclaimed.
One of the areas in a VM that can take up a lot of disk space is the repository cache. So I personally tend to clean the cache in the VM before reclaiming disk space at the host.
Clean up your repositories:
For example, on Debian-based VMs, you can run the following command (in the VM)
apt-get clean all
to clear out the local repository of retrieved package files.
On red hat based VMs that would be:
yum clean
The next step is important:
Shut down any services that depend on having enough available disk space to run.
The reason for this is that we are going to write out zero's to the file system until the file system is full and we do not want any application - for example a database system like mySQL or postgreSQL - to run out of disk space while we are zeroing out the file system. If mySQL would try to write when your disk is full you risk a corrupted database. So this step is important!
Next run (also from within the VM):
cat /dev/zero > zero.fill;sync;sleep 1;sync;rm -f zero.fill
to fill the unused space with zeros and then remove the "zero.fill" that has all the zero's.
As this command writes to the disk until it runs out of disk space, you will get an error "No space left on the device". This is expected.
Note that you have multiple partitions that you have to repeat the above command to zero out for each partition. Adjust "zero.fill" to the relevant mountpoint, for example if you have a separate partition for home it would become:
cat /dev/zero > /home/zero.fill;sync;sleep 1;sync;rm -f /home/zero.fill
Zero out a part of your virtual disk
If your virtual machine cannot be taken down and you do not want to shut down services that might end up corrupting files because of the "No space left on the device" problem then an idea that might work is to zero out a part of your partition.
This for example creates a 100MB size file filled with zero's
# dd if=/dev/zero of=zero.fill bs=1024 count=102400 102400+0 records in 102400+0 records out 104857600 bytes (105 MB) copied, 0.3839 s, 273 MB/s
So if you want to zero out 10GB instead, add two more zero's to the count parameter, eg: count=10240000
If you want to fill up in steps, just change the output file name from "zero.fill" into "zero.fill2" etcetera..
Then run the "sync; sleep 1; sync" from above and remove the zero.fill files.
If your VM is running on VMware vSphere and you have a NFS LUN with enough free space then one way to reclaim your space is to Storage vMotion the VM to NFS storage and back. Once done the zero'd out data has been reclaimed. No need to shut down the VM.
If this is not for you, then do read on.
Zero out using fstrim
These days there's an alternative way for zero-ing out the parts of the disk that are not used using fstrim.
eg:
# fstrim -a -v /var: 274.3 MiB (287592448 bytes) trimmed on /dev/sda3 /tmp: 63 MiB (66060288 bytes) trimmed on /dev/sda5 /home: 125 MiB (131072000 bytes) trimmed on /dev/sda6 /boot/efi: 505.2 MiB (529735680 bytes) trimmed on /dev/sda1 /: 5 MiB (5242880 bytes) trimmed on /dev/sda2
The great thing about this is that it only zero's out the parts of the disk that are not zero and as such the disk does not inflate to its full size.
On most modern systems fstrim is being run automatically using systemctl. You can check if it is enabled:
# systemctl status fstrim.timer ● fstrim.timer - Discard unused blocks once a week Loaded: loaded (/lib/systemd/system/fstrim.timer; disabled; vendor preset: enabled) Active: inactive (dead) Trigger: n/a Triggers: ● fstrim.service Docs: man:fstrim
Oh-huh, our system does not have it enabled.. might there be a reason, such as that the UNMAP command is not supported? If so, the following command would return 0.
# cat /sys/block/sda/queue/discard_max_bytes 1073741824
So UNMAP is supported, but fstrim still is not enabled, lets fix that.
# systemctl enable fstrim.timer Created symlink /etc/systemd/system/timers.target.wants/fstrim.timer → /lib/systemd/system/fstrim.timer.
and reload systemctl plus check that it now works...
# systemctl start fstrim.timer # systemctl daemon-reload # systemctl status fstrim.timer ● fstrim.timer - Discard unused blocks once a week Loaded: loaded (/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled) Active: active (waiting) since Sat 2024-01-06 13:00:46 CET; 6s ago Trigger: Mon 2024-01-08 01:17:59 CET; 1 day 12h left Triggers: ● fstrim.service Docs: man:fstrim
see also:
Zero out unused space on a Windows VM
To do the same with a windows VM, you can use Microsoft's tool sdelete.
Run it as
sdelete -z c:
To clean out the free space on disk c:
Careful!
As of sdelete v1.6 -c and -z have changed meanings, many instructions say -c zeros free space, this is no longer the case, it zeros the space then fills with random data in accordance with DOD spec: DOD 5220.22-M, random data will prevent the reclaim logic from working.
The trigger to zero space with 0x00 has changed to -z!
Zeroing an encrypted disk
If you use disk encryption in the guest OS then zero'ing out the disk won't help.
The reason is that a good disk encryption scheme will write out random data to the disk when you write out zero's.
In other words, if you have enabled full disk encryption in the guest then you can not shrink the disk anymore as there is no space to reclaim.
Shrink the disk
Then power down the VM and open a terminal on the Linux host.
Navigate to the directory where the .vmdk files are located, e.g.:
cd /var/lib/vmware/Virtual\ Machines/Ubuntu\ Desktop/
You can shrink the .vmdk file as follows:
vmware-vdiskmanager -k Ubuntu\ Desktop.vmdk
On Windows the command also uses the -k option, so I leave that for you as an exercise.
Note that vmware-vdiskmanager is probably not in your search path, so you might have to prepend the vmware-vdiskmanager command with the actual path with the command is located.
On macOS you run it as:
/Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -k Ubuntu\ Desktop.vmdk
If you need to use "sudo" in order to be able to run the above then beware that the ownership of the .vmdk files might get changed to root. So certainly try it first without running as root!
You will have to change the ownership back to your own user, eg:
sudo chown username: *.vmdk
If you don't change the ownership back you might see errors like:
"Unable to open file .../Virtual Disk.vmdk: Insufficient permission to access file".
Shrink using vmware tools
Nowadays you can also shrink the guest by using the shrink feature as offered via vmware tools.
So for clarity all of the following commands are run from within the guest to shrink the disk while the guest is running.
On linux in order to use this run:
sudo vmware-toolbox-cmd disk shrink /
Where "/" is the mount point of the partition that you want to shrink.
On Windows in order to use this run (as administrator):
C:\Program Files\VMware\VMware Tools>VMwareToolboxCmd.exe disk shrink <location>
where <location> is the drive you want to shrink
For example:
C:\Program Files\VMware\VMware Tools>VMwareToolboxCmd.exe disk shrink c:\ Please disregard any warnings about disk space for the duration of shrink process. Progress: 62 [=======> ]
The progress you see here is VMware Tools blanking out the unused space.
At 99% it will popup the "Shrinking Disk" progress dialog at the host that takes care of the actual shrinking process.
If you are logged in via remote desktop then do expect to loose the connection for a bit while the actual shrinking is taking place.
On OS X / macOS the command to use is:
sudo /Library/Application\ Support/VMware\ Tools/vmware-tools-cli disk shrink /
Shrink macOS VM with APFS
Solved: Shrink an APFS virtual disk