Case study
Docker Control Center
MaintainedWhat Docker Desktop does, in the terminal. A script with no UI, no daemon and nothing resident, for servers where you cannot install that.
The problem
Docker Desktop handles the day to day well: containers, images, logs, states. But it wants a graphical interface and a daemon running, and neither exists on a server.
It started as a Makefile with aliases for the commands I kept repeating. It worked, but a
Makefile does not travel: it depends on being in the right directory and on having make
installed.
So it became a script.
What it is
A Docker control panel that runs in the terminal: containers, images and their state, without leaving the SSH session.
$ dcc dash
DOCKER · default · engine 29.6.2 · 8 CPU · overlayfs · host RAM 412 MB
────────────────────────────────────────────────────────────────────────────────
2 stacks · 4/6 containers up · CPU 6.3% of host · 21.4 GB on disk
IDENTIFIED WASTE (counted from the API, not estimated by docker)
build cache 4.2 GB 12 entries, 0 in use dcc clean-build
stopped layer 912 MB 2 containers dcc clean
unused images 1.0 GB node:18, postgres:15 dcc clean
orphan volumes 30 MB 2 unmounted dcc volumes-orphan
6.1 GB verified
And the interesting part is not the listing: it is counting the waste from the API rather than estimating it, and telling you the exact command that clears it.
It does what Docker Desktop does, but without installing any of that — no UI, no daemon. Scripts only, so it works the same in a development environment as in production.
Constraints
- No GUI and no daemon. It installs nothing, leaves nothing running and needs no permissions beyond the ones already required to talk to Docker.
- Scripts only. That is what makes it usable in production without asking anyone’s permission.
These are systems-administration constraints, not development ones: on someone else’s server, what matters is leaving no trace.
Decisions
From Makefile to script
Context. The aliases lived in a Makefile. It worked on my machine.
Decision. Rewrite it as a script.
Why. Two reasons, both the same project constraint pushed one step further:
- Dependencies. Ubuntu ships
make, but not every distribution does. A tool whose entire argument is “install nothing” cannot open by requiringmake. - Invocation. A script goes on the
PATHand is called by name from any directory. I use it asdcc. AMakefileties you to the directory it sits in.
Consequences. Everything make gave for free — subcommand dispatch, help, the target list —
becomes your own code. More code in exchange for fewer requirements, and that trade leads straight
into the next section.
What I would do differently
Less code.
It went from a single file that was not that large to considerably more code, and a good part of that was trying to impress. If I rebuilt it, I would simplify.
That said, making it robust forced me to learn the shell development toolchain — testing, translations — which I did not know. In that sense it paid for itself.
Status
In use and maintained. Bilingual, tested with ShellSpec, documentation published. Open source, MIT licensed.
Still to write
TODO