One day, I was looking for some gains to improve the startup time for Jenkins agents. We run them as containers and because images are quite big, I was thinking about cutting the size, by cutting less frequently used features. I was looking for the metrics I could use to decide which changes are most valuable. I could think about two: download time and startup time. Together they combine to the gap between the request to start agent and the moment you can start to use it. Sadly it wasn’t that easy to measure that and collect statistics. It’s also not that practical, when you’re developing improvement as you can’t see the difference.

I started thinking about alternative metrics and I quickly figured out, that I can check Docker image compressed size. It would be proportional to the download time. I can also compare compressed size with uncompressed size as it will show how much data have to be extracted, being proportional to the startup time. Although those KPIs are not as good, they’re fairy ok to use during development.

Then I found, it’s not that easy to guess compressed size of Docker image. docker image ls shows extracted size. docker inspect shows compressed size per layer. Luckily I found1 nice bash function that can make the whole process easy:

Simple function to guess compressed size of image
dockersize() { docker manifest inspect -v "$1" | jq -c 'if type == "array" then .[] else . end' |  jq -r '[ ( .Descriptor.platform | [ .os, .architecture, .variant, ."os.version" ] | del(..|nulls) | join("/") ), ( [ .SchemaV2Manifest.layers[].size ] | add ) ] | join(" ")' | numfmt --to iec --format '%.2f' --field 2 | column -t ; }

Now it’s easy to imagine download time impact and gains from my work:

Usage of dockersize
$ docker pull alpine
$ docker pull python

$ docker image ls
python       latest    33039c2f184f   5 weeks ago   1.02GB
alpine       latest    1dc785547989   7 weeks ago   7.73MB

$ dockersize alpine
linux/amd64     3.26M
linux/arm/v6    3.02M
linux/arm/v7    2.79M
linux/arm64/v8  3.20M
linux/386       3.10M
linux/ppc64le   3.21M
linux/s390x     3.10M

$ dockersize python
linux/amd64                    362.96M
linux/arm/v5                   330.63M
linux/arm/v7                   316.31M
linux/arm64/v8                 353.81M
linux/386                      365.13M
linux/ppc64le                  377.20M
linux/s390x                    333.43M
windows/amd64/10.0.20348.2227  1.83G
windows/amd64/10.0.17763.5329  1.99G