Most Docker images consist of multiple superimposed filesystems. When a container is started, a new empty layer is stacked on top which captures all filesystem writes during the container's execution.
This allows the following features:
- After the container stops running, these layers can be combined into a new image. This is what happens when you build images.
- The original image is never changed and can be used at any time to start a new container.
- When a new version of the application is released, it is not necessary to rebuild the whole image from scratch. You just start from the layers below.
If you're deploying to a system under systemd, you can run anything that looks like a sysroot using nspawn. I find this much more enjoyable than going through the huge sidecar that is the Docker runtime.
Not quite sure if it's related, but this is why I've been hesitant to go down the Docker rabbit hole that so many devs are pursuing these days.
On the one hand, I absolutely see the value of 'disposable' containers: discarding flaky instances and rebuilding a pristine one from a version-controlled config (i.e. "turn it off and on again").
However, the mechanisms to do that (re)building seem to consist of an unreproducible opaque binary blob (a "base image"), which gets augmented by a sequence of highly imperative commands; usually doing completely unpredictable things like 'apt-get update && apt-get install -y foo'.
I want the former, but the latter seems like a massive step backwards. I've seen some work on building Docker "images" using Nix, so that's the path I ultimately want to try. Colleagues may take some convincing though!