A (very dirty) experiment to remove layers from a Docker image.
Requirements:
- Docker Engine
- Skopeo
- Python 3
Build a trivial Docker image:
docker build example/ -t figlet
Export it to an OCI directory, so that we can mess with it:
OCI_DIR=src
skopeo copy docker-daemon:figlet:latest oci:$OCI_DIR
Run the horrible script:
./layeremove.py $OCI_DIR
Copy the updated image back to the Docker Engine:
skopeo copy oci:$OCI_DIR docker-daemon:figlet:layeremove
Check that the image still works:
docker run figlet:layeremove
Check the size and layers of the original and new image:
docker images figlet
docker history figlet:latest
docker history figlet:layeremove
The layeremove.py
script will scan an OCI image, and it will remove
some layers from that image. It will layers that contain #LAYEREMOVE#
in their created_by
attribute; so if you put RUN something #LAYEREMOVE#
in a Dockerfile, the resulting layer will be removed. You can also pass
layer hashes as extra command line arguments, e.g.:
./layeremove.py oci-src-dir sha256:abc123... sha256:def678...
It identifies the layers, then removes them from the image manifest
as well as the image configuration. In the image configuration, it
leaves a dummy layer in the history, which is why these layers will
still show up in docker history
.
The code worked for me at least once, but there is no guarantee that it will work for you! 🤷🏻
Make sure that the OCI directory contains only one image. Otherwise, adapt things a bit.
The code deserves to be cleaned up a bit, but I think I'll go and have a beer instead! 🍺