Clean up qcow2 in Docker on MacBook

I really enjoy figuring out stuff to do with DOCKER, but I recently tweeted the following:

Twitter

Why you ask? Well, there is this file, Docker.qcow2 located right here:
 ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2
 on my MacBook Pro that consumes all of the remaining space I have on my hard drive, and SSD’s ain’t cheap. I’m sure I need to clean up some stuff myself, but that’s not the point of this post. I want Docker to manage this file. Deleting images or containers has no impact on this file. It just continues to GROW.

Space consumption
and now

So this is the impetus for the blog post today.

A quick Google search shows that this issue is not new and is obviously still present in the most recent release as of this post.

Version

Here is the issue according to the Docker forums:
 “The qcow file is a block disk image that grows when unwritten blocks in the 64GB virtual device are written so the sparsity of writes due to ext4 disk layout causes an initially large increase in image size.”

Since I am working with mainly the Oracle 12.1 image, which is in the 5+GB range, space is at a premium and so here’s to hoping they find a solution sooner than later as it is at a minimum inconvenient to have to do either one of these processes.

I have found two ways to work around this issue of my Mac experiencing disk space issues as a result of testing with Docker.

bomb

Yep! Bomb the crap out of Docker by going into the Docker -> Preferences menu and clicking that Reset icon.

Docker Preference Scree

And this works, but you will loose all your images and containers if you don’t take some steps to preserve them. What can we do?

The docker save command produces a .tar file to STDOUT. The -o option writes to a file instead of STDOUT.

You can then go ahead and reset Docker. Once the reset has completed, the docker load command will load a .tar or the standard input stream. It restores both images and tags. This important since other applications outside of Docker may reference the image IDs.

In this example you would:

  1. docker save your images. Use docker images to identify the images you want to save
  2. Reset Docker from the Preferences menu
  3. docker load your images from the .tar files created in step 1

The other option I had was to script all this. Fortunately, this the internet and this issue is not unique. I found a script by Théo Chamley, that basically did exactly what I was looking for. I took the liberty of making a few modifications to meet my specific needs.

  • Disk space was an issues so I am storing image archives on an NAS instead of locally
  • I may want to save my images archives
  • and since I planned to share this code, I added some instructions and options to exit before the process started.

With this script in hand, all you need to do is identify the docker image IDs (docker images) then enter them as arguments separated by spaces for the scripts.

This script basically performs the following:

  1. Reads Image IDs as script arguments
  2. Assign the temp dir to a local variable
  3. Executes docker save for each image in argument list and saves them
  4. Stops the Docker app
  5. Deletes the Docker.qcow2 file (this is the problem file)
  6. Starts the Docker app
  7. Executes docker load to restore the archived images
  8. Either deletes or keeps archived images (Y/N)

You can visit my Github Repo find the script here or copy it from below

— — Script — —

#!/bin/bash
# Copyright 2017 Théo Chamley
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
# to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

# Array to hold image IDs. Note that it is not necessary to provide the entire
# image ID. Just the first few characters is sufficient.
# Use "docker images" at the command prompt to find image IDs
# Image IDs are entered on the command line separate by a space.

# Changelog
# Added instructional language prior to script execution - DB

# Added ability to exit the script in the event that user failed to include
# a key requirement - DB

# Change code to use an environment variable for location to write image archives -DB

# Added option to not delete archived docker images after Docker reset
IMAGES=$@
clear

echo "This script is designed to help address the growth of the Docker.qcow2 file by:"
echo "1. backing up the image IDs you identify at the command line to a temp directory"
echo "2. removing any containers and images NOT listed below"
echo "3. deleting the Docker.qcow2 file"
echo "4. restoring your image backups"
echo "5. and offering to delete the those backup files."
echo
echo "****You will loose all of your images if you do not provide the IMAGE IDs on the command line.****"
echo "The script will use the directory identified by the TMP_DIR environment variable,"
echo "or you may set this variable using the 'EXPORT TMP_DIR=<directory>' command prior to running the script."
echo "If you need to exit this script for any reason please do so now."
read -p "Exit? [yes/no] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]
then
exit
else

echo "Backup and restore the following images:"
echo ${IMAGES}
read -p "Are you sure? [yes/no] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
exit
fi
# Assign local variable to TMP_DIR location either from enviroment variable
# in profile or via EXPORT TMP_DIR command
my_dir=$(echo $TMP_DIR)
pushd $my_dir >/dev/null

# Use the Docker save command to save images
open -a Docker
echo "Saving images. Please note that large images can take some time to archive."
for image in ${IMAGES}; do
echo "Saving ${image}"
tar=$(echo -n ${image} | base64)
docker save -o ${tar}.tar ${image}
echo "Done."
done

echo -n "Quiting Docker"
osascript -e 'quit app "Docker"'
while docker info >/dev/null 2>&1; do
echo -n "."
sleep 1
done;
#!/bin/bash
echo ""

echo "Removing the problem child --> Docker.qcow2 file"
rm ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2

echo "Restarting Docker application."
open -a Docker
until docker info >/dev/null 2>&1; do
echo -n "."
sleep 1
done;
echo

echo "Restart Complete!"

echo "Restoring images from archive."
for image in ${IMAGES}; do
tar=$(echo -n ${image} | base64)
docker load -q -i ${tar}.tar || exit 1
echo "==> Done."
done

popd >/dev/null

# Delete archived Images
echo "Would you like it delete archived image(s)?"
echo ${IMAGES}
read -p "[yes/no] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
exit
fi

echo "Deleting saved images."
cd $my_dir
rm *.tar
fi

Enjoy


Originally published at dbaonTap.

Show your support

Clapping shows how much you appreciated Danny Bryant’s story.