Why does the file keep growing?
If Docker is used regularly, the size of the  Docker.raw  (or  Docker.qcow2) can keep growing, even when files are deleted.
To demonstrate the effect, first check the  current  size of the file on the host:
$ cd ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/
$ ls -s Docker.raw
9964528 Docker.raw
Note the use of  -s  which displays the number of filesystem blocks actually used by the file. The number of blocks used is not necessarily the same as the file “size”, as the file can be  sparse.
Next start a container in a separate terminal and create a 1GiB file in it:
$ docker run -it alpine sh
# and then inside the container:
/ # dd if=/dev/zero of=1GiB bs=1048576 count=1024
1024+0 records in
1024+0 records out
/ # sync
Back on the host check the file size again:
$ ls -s Docker.raw 
12061704 Docker.raw
Note the increase in size from  9964528  to  12061704, where the increase of  2097176 512-byte sectors is approximately 1GiB, as expected. If you switch back to the  alpine  container terminal and delete the file:
/ # rm -f 1GiB
/ # sync
then check the file on the host:
$ ls -s Docker.raw 
12059672 Docker.raw
The file has not got any smaller! Whatever has happened to the file inside the VM, the host doesn’t seem to know about it.
Next if you re-create the “same”  1GiB  file in the container again and then check the size again you will see:
$ ls -s Docker.raw 
14109456 Docker.raw
It’s got even bigger! It seems that if you create and destroy files in a loop, the size of the  Docker.raw  (or  Docker.qcow2) will increase up to the upper limit (currently set to 64 GiB), even if the filesystem inside the VM is relatively empty.
The explanation for this odd behaviour lies with how filesystems typically manage blocks. When a file is to be created or extended, the filesystem will find a free block and add it to the file. When a file is removed, the blocks become “free” from the filesystem’s point of view, but no-one tells the disk device. Making matters worse, the newly-freed blocks might not be re-used straight away – it’s completely up to the filesystem’s block allocation algorithm. For example, the algorithm might be designed to favour allocating blocks contiguously for a file: recently-freed blocks are unlikely to be in the ideal place for the file being extended.
Since the block allocator in practice tends to favour unused blocks, the result is that the  Docker.raw  (or  Docker.qcow2) will constantly accumulate new blocks, many of which contain stale data. The file on the host gets larger and larger, even though the filesystem inside the VM still reports plenty of free space.
TRIM
A  TRIM  command (or a  DISCARD  or  UNMAP) allows a filesystem to signal to a disk that a range of sectors contain stale data and they can be forgotten. This allows:
- an SSD drive to erase and reuse the space, rather than spend time shuffling it around; and
 
- Docker for Mac to deallocate the blocks in the host filesystem, shrinking the file.
 
So how do we make this work?
Automatic TRIM in Docker for Mac
In Docker for Mac 17.11 there is a  containerd  “task” called  trim-after-delete  listening for Docker image deletion events. It can be seen via the  ctr  command:
$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n ctr t ls
TASK                    PID     STATUS    
vsudd                   1741    RUNNING
acpid                   871     RUNNING
diagnose                913     RUNNING
docker-ce               958     RUNNING
host-timesync-daemon    1046    RUNNING
ntpd                    1109    RUNNING
trim-after-delete       1339    RUNNING
vpnkit-forwarder        1550    RUNNING
When an image deletion event is received, the process waits for a few seconds (in case other images are being deleted, for example as part of a  docker system prune  ) and then runs  fstrim  on the filesystem.
Returning to the example in the previous section, if you delete the 1 GiB file inside the  alpine  container
/ # rm -f 1GiB
then run  fstrim  manually from a terminal in the host:
$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n fstrim /var/lib/docker
then check the file size:
$ ls -s Docker.raw 
9965016 Docker.raw
The file is back to (approximately) it’s original size – the space has finally been freed!
Hopefully this blog will be helpful, also checkout the following macos docker utility scripts for this problem:
https://github.com/wanliqun/macos_docker_toolkit