For image and layer manipulation, crane is awesome - as is the underlying go-containerregistry library.
It lets you add new layers, or edit any metadata (env vars, labels, entrypoint, etc) in existing images. You can also "flatten" an image with multiple layers into a single layer. Additionally you can "rebase" an image (re-apply your changes onto a new/updated base image). It does all this directly in the registry, so no docker needed (though it's still useful for creating the original image).
https://github.com/google/go-containerregistry/blob/main/cmd...
(updated: better link)
Is there any performance benefit to having fewer layers? My understanding is that there's no gain by merging layers as the size of the image remains constant.
If you've got a 50 layer image then each time you open a file, I believe the kernel has to look for that file in all 50 layers before it can fail with ENOENT.
That seems ripe for optimization, if true, especially since those layers are all immutable.
A container runtime could optimize for speed by unpacking all those layers one by one into a single lower directory for the container to use; but at the cost of using lots of disk space, since those layers would no longer be shared between different containers.
It depends on your OCI engine; but this isn’t the case with containers. Each layer is successively “unpacked” upon a “snapshot”, from which containers are created.
Interesting. Certainly with podman I observe that the layers are combined by overlayfs.
I build this Dockerfile into a container with 'podman build -t test .':
Then run it with 'podman run --rm -it test':Then I can inspect the container's storage configuration:
Note that there are four directories in the LowerDir, and examining their contents reveals that there's one per layer in my 'test' image: Same for a system (non-rootless) container: ('podman system info' confirms that .store.graphDriverName == "overlay")I'd be interested to see what this looks like with docker?
some startup performance savings in fewer http requests to fetch the image. small for sure but it's something?
Depends. If you would have to fetch a big layer often because of updates, that's not good. But if what is changing frequently is in a smaller layer, it will be more favorable
In practice I've found the performance savings often goes the other way--for large (multi-GB) images it's faster to split it up into more layers that it can download in parallel from the registry. It won't parallelize the download of a single layer and in EC2+ECR you won't get particularly good throughput with a single layer.
Eventually, once zstd support gets fully supported, and tiny gzip compression windows are not a limitation, then compressing a full layer would almost certainly have a better ratio over several smaller layers
https://github.com/opencontainers/image-spec/issues/803
Is it coming? That ticket doesn't fill me with hope, given its age and the disagreements over backwards compatibility.
I'm working on a tool that does the opposite: to split layers into smaller, deterministic deltas.
If files are overwritten or removed in a lower layer, there can be size savings from that.
Less performance and more security. Lots of ameteur images use a secret file or inadvertently store a secret to a layer without realizing an rm or other process in another layer doesn't actually eliminate it. If the final step of your build squashes the filesystem flat again you can remove a lot of potentially exposed metadata and secrets stored in intermediate layers
There are some useful cases — for example, if you're taking a rather bloated image as a base and trimming it down with `rm` commands, those will be saved as differential layers, which will not reduce the size of the final image in the slightest. Only merging will actually "register" these deletions.
This is a great recommendation. It is worth noting that unlike Docker, crane is root- and daemonless which makes it work great in Nix (it's called 'crane' in the Nix repository). This allows for Nix to be used to manage dependencies for both building (e.g. Go) as well as packaging and deploying (e.g. gnu tar, crane).