Injectable builder (and friends)

The goal of these changes is to make everything easier to test, and follow the flow of control through from the top down. Tests can now e.g. inject a faked out docker client to assert that the builder does the right thing, or a faked out runner to assert that the various hooks execute the correct build tasks.

We've made an attempt to break what's effectively a lot of churn into smaller commits that act as a progression. Also made sure that existing singletons are still initialized only once (i.e. `docker.DefaultClient`).

This is still a WIP. More to come!

/cc @hiremaga