Technology, open source, unsolicited opinions & digital sovereignty

« The Best Thing About Docker is not Docker »

  • 27 September, 2022
  • 515 words
  • two minutes read time

Docker is the de facto solution for packaging most server-side applications these days. The technical merits of Docker are nifty – cgroups and other mechanisms are certainly useful – but there’s one particular aspect of running an application in Docker that has been unequivocally beneficial for the industry: concretely defined inputs and outputs.

I was reading the Gitea installation docs the other day when I realized why I gravitate immediately to the “Installation with Docker” section even when Docker may not be my deployment strategy. I do so because a file like docker-compose.yml is a manifest that defines in certain terms how a program interacts with its environment in a concise, standard way.

When I run an application in an environment like my homelab, there’s a constant list of things that I, as an operator, need to know:

Part of why each of those bullets is useful is that, without those various settings, a container is – almost by definition – an inert unit of compute and nothing more. It can only rely on persistent storage or inbound traffic if you explicitly configure the container to do so. Is that Gitea container leaving other files scattered around or leaving a port listener undocumented? Probably not, because otherwise the userbase would find out about broken or buggy containers pretty quickly. The container image can’t receive traffic on a port that the developers have failed to document as part of a container configuration.

Frankly, this is why my gut feeling is that the kubernetes “revolution” that is eating DevOps feels marginally less significant to me than Docker itself. Sure, k8s is a nice abstraction layer over your hypervisors or container runtime, but the real meat – the juicy, high-fructose center – of what Docker brought to us was the application manifest. Do you feel a really gut-wrenching pull to docker run rather than invoking an ./app statically-compiled binary based primarily on the runtime? I’ll probably end up putting the ./app in a cgroup’d systemd Unit anyway, but I absolutely want the instructions to run it to be consistent.