$ make docker

Mar 31, 2022

What would you use for a build system in a greenfield project? package.json runners are too slow and language-specific. Bazel, pants, and buck are overkill for most any company. Shell scripts are a good option, but are too freeform to provide basic tools any build system needs (like caching or rule matching and dispatch). Dockerfiles are great and should contain the majority of the build, but aren't expressive enough for an entire build system.

Even in a world where most of the build process is embedded in a docker build, I still find myself going for make.

make gives you a lot for free. Basic caching (based on file last modified time). Simple pattern matching with wildcards and substitution (automatic rules). Escape hatch for everything else (PHONY rules). Primitive modularity (`include` other Makefiles, recursive calls).

While the make syntax could use a refresh (it was first developed in 1976), there's a more fundamental shift in how our build commands run. Instead of just running the commands in a shell, we'd ideally want to run them in Docker (specifically, Buildkit). Essentially, running commands in a completely isolated and controlled environment – controlling what tools are installed, what caches are mounted, what files are accessible, and everything else. Docker provides the engine for this, but right now the only way to utilize the engine is through the Dockerfile – which wasn't made for this.

Therein lies the next problem frontier for build tooling – converting the user-specified build graph (DAG) to Buildkit's low-level build language (also a DAG). I wrote a tutorial (and gave a talk on) how to do this back in 2019 (see: An Alternative to the Dockerfile).

There's two interesting startups in this space: Earthly and Dagger. Earthly has adopted a hybrid Dockerfile/Makefile syntax to determine the build graph. Dagger uses a new configuration language out of Google called CUE. I don't know what the business model or right answer here is.

Maybe one day I'll release a compiler for virgo lang to Buildkit (since it's just another DAG-to-DAG problem).