Querying and comparing the size of different docker image tags from the command line can be as easy as follows:
docker run --rm schnatterer/docker-image-size <docker image name> [<extended grep regex on docker tag>] # e.g. docker run --rm schnatterer/docker-image-size adoptopenjdk '^11.0.4' \ | grep 'amd64 linux' # A single image size can be queried faster like so docker run --rm --entrypoint docker-image-size-curl.sh schnatterer/docker-image-size adoptopenjdk:11.0.4_11-jre-hotspot
Unfortunately, it’s takes minutes.
When starting a new project, building a CI/CD pipeline or when deploying an app off the shelf we often have the challenge of selecting not only a suitable docker / OCI image but also which tag of the image to use.
The trouble at Docker Hub
The first stop is usually on hub.docker.com where it is confusing to select among the different versions, variants and architectures, e.g. JDK, node, ruby or .net (which does not even have tags on docker hub).
reg to the rescue
In situations such as these genuinetools/reg is very helpful to get a textual overview of all tags of a repo on the command line which can easily be grepped for what is needed. For example:
reg tags adoptopenjdk | grep 11.0.4 # We can apply more complex regex reg tags adoptopenjdk | grep -P '^(?!.*windows)11.0.4' # Actually we don't even need to install reg, we can just user docker for distribution docker run r.j3ss.co/reg tags openjdk | grep -e '^11.0.4-' # BTW I use: alias reg='docker run r.j3ss.co/reg' # Every now and then I update like so docker pull r.j3ss.co/reg
One thing that is missing though, is the image size. It’s not that important but it gives a hint which tags point to the same image and also might be another fact to choose or not to choose one image over the other.
While preparing one of my docker training courses, I answered a question on stackoverflow on how Docker Hub sums up the image size. After that I found myself returning to my own answer every now and then because I wanted to reuse the script for finding out image sizes via the command line.
Having done this too often, I decided to implement a script that does this more convenient: schnatterer/docker-image-size.
It turned out to become four scripts, actually:
- Three for the different ways of querying docker manifests (
docker manifestand via
- and another one that uses the above one and combines it with the
reg tagscommand for comparing image sizes.
They also come neatly packed into a docker image, and can be used like so:
docker run --rm schnatterer/docker-image-size <docker image name> [<extended grep regex on docker tag>] # If used more often, an alias provides more convenience: alias docker-image-sizes='docker run --rm -e DIS_IMPL schnatterer/docker-image-size' docker-image-sizes <docker image name> [<extended grep regex on docker tag>]
While implementing, I completely underestimated the peculiarities of the docker distribution protocol (standardized as OCI distribution spec), with all those different implementations in registries (Docker Hub, MCR, GCR, quay.io, etc.), multiple architectures, repo digests, manifest versions (V1 vs V2) and docker login. This lead to the different implementations providing different features:
docker manifest seems like the most versatile solution, being compatible with most repos. Unfortunately, querying a single manifest might take more than 10 seconds.
Still, we can now easily compare different tags of docker image using the following commands, for example:
# Match all tags containing '11' (a whole lot. Will take ages!) docker-image-sizes adoptopenjdk 11 # More accurate (and faster) output docker-image-sizes adoptopenjdk '^11.0.4' # Multi arg results can be filtered using grep docker-image-sizes adoptopenjdk '^11.0.4' | grep 'amd64 linux'
The results will take some minutes (as mentioned above) and look like this:
adoptopenjdk:11.0.4_11-jdk-hotspot amd64 linux : 235 MB adoptopenjdk:11.0.4_11-jdk-hotspot-bionic amd64 linux : 235 MB adoptopenjdk:11.0.4_11-jdk-openj9-0.15.1 amd64 linux : 236 MB adoptopenjdk:11.0.4_11-jdk-openj9-0.15.1-bionic amd64 linux : 236 MB adoptopenjdk:11.0.4_11-jre-hotspot amd64 linux : 80 MB adoptopenjdk:11.0.4_11-jre-hotspot-bionic amd64 linux : 80 MB adoptopenjdk:11.0.4_11-jre-openj9-0.15.1 amd64 linux : 79 MB adoptopenjdk:11.0.4_11-jre-openj9-0.15.1-bionic amd64 linux : 79 MB
If we don’t care about multi-arch anyway, we could use the curl implementation like so:
DIS_IMPL=curl docker-image-sizes adoptopenjdk '^11.0.4' 2>/dev/null
This results in a much faster response (about a minute), but fails for the windows variants (which we generously pipe to
Querying the size of a single image
If you care about size of one image only you can use the implementations directly, which for the curl implementation responds in about a second. Note that it takes only one parameter, similar to
$ docker-image-size-curl.sh adoptopenjdk:11.0.4_11-jre-hotspot # Or using the docker image $ docker run --rm --entrypoint docker-image-size-curl.sh schnatterer/docker-image-size adoptopenjdk:11.0.4_11-jre-hotspot adoptopenjdk:11.0.4_11-jre-hotspot: 80 MB # If used more often, an alias provides more convenience: $ alias docker-image-size='docker run --rm --entrypoint docker-image-size-curl.sh schnatterer/docker-image-size'
The largest image ever
Fun fact at the end: Using docker-images-sizes, I found the largest image I ever (?):
adoptopenjdk:11.0.4_11-jdk-hotspot amd64 windows 10.0.14393.3204: 6100 MB
It still makes me smirk that a “leightweight” docker image for Windows is 67x the size of a whole Linux VM:
$ docker-image-sizes weaveworks/ignite-kernel 4.19.47 weaveworks/ignite-kernel:4.19.47: 14 MB $ docker-image-sizes weaveworks/ignite-ubuntu 19.04-v0.5.2 weaveworks/ignite-ubuntu:19.04-v0.5.2: 77 MB