In Part 3 we managed to build a Docker image containing the tools required to compile and link C/C++ code destined for our embedded Arm target system. However, we’ve paid little attention to the size of the image. Doing a quick Docker image listing we can see its grown to a whopping 2.14GB:
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE feabhas/gcc-arm-scons 1.0 6187455a4bfe 8 days ago 2.14GB gcc 7.2 7d9419e269c3 2 months ago 1.64GB
In your day-to-day work the size of a Docker image may not bother you as Docker caches images locally on your machine. But after a while you’ll certainly need to prune them.
Apart from freeing up disk space, why else look to reduce the size of an image?
As previously mentioned, the overriding benefit of using a Docker-based build is consistency and repeatability of the build. But, for modern CI to be effective, we want the build/test cycle to be as quick as possible.
A local provisioned build server (such as a Linux server running Jenkins) will also cache images after the first build, so less of an issue.
Cloud-based CI services (such as the previously-mentioned Travis-CI, Bitbucket, Gitlabs, etc.) are typically costed on build-minutes for a given period, e.g. build-minutes per month. In these cases pulling or building larger images naturally takes longer; and costs more.
Generating Smaller Images
There is plenty of good guidance around, and I’m sure what I’m doing here can be improved up on. Our basic approach to minimise our image consists of these steps:
- Start with a minimal Base image
- Only install what we need
- Remove anything we only needed to help install what we needed!
- Reduce the number of Docker layers
Minimal Base Image
Our base image is gcc:7.2 which comes in at 1.64GB. To that we added Scons and the gcc-arm cross compiler, but for cross-compilation we don’t require the host GCC (x86) compiler.