> builds are performed "inside out" and aren't reproducible
This is probably a good argument because of how hard it is to do anything in a reproducible manner, if you care even about timestamps and such matching up.
Yet, i'd like to disagree that it's because of inherent flaws with Docker, merely how most people choose to build their software. Nobody wants to use their own Nexus instance as a storage for a small set of audited dependencies, configure it to be the only source for all of them, build their own base images, seek out alternatives for all of the web integrated build plugins etc.
Most people just want to feed the machine a single Dockerfile (or the technology specific equivalent, e.g. pom.xml) and get something that works out and thus the concerns around reproducibility get neglected. Just look at how much effort the folks over at Debian have put into reproducibility: https://wiki.debian.org/ReproducibleBuilds
That said, a decent middle ground is to use a package cache for your app dependencies, specific pinned versions of base images (or build your own ones on top of the common ones, e.g. a customized Alpine base image) and multi stage builds, you are probably 80% of the way there, since if need be, you could just dump the image's file system and diff it against a known copy.
Nexus (some prefer Artifactory, some other solutions): https://www.sonatype.com/products/repository-oss
Multi stage builds: https://docs.docker.com/develop/develop-images/multistage-bu...
The rest 20% might take a decade until reproducibility is as user friendly as Docker currently is, just look at how slowly Nix is adopted.
> publishing produces unauditable binary-blobs
It's just a file system that consists of a bunch of layers, isn't it? What prevents you from doing:
docker run --name dump-test alpine:some-very-specific-version sh -c exit
docker export -o alpine.tar dump-test
docker rm dump-test
You get an archive that's the full file system of the container. Of course, you still need to check everything that's actually inside of it and where it came from (at least the image persists the information about how it was built normally), but to me it definitely seems doable
> consumption bypasses cryptographic security by fetching "latest" tags
I'm not sure how security is bypassed if the user chooses to use whatever is the latest released version. That just seems like a bad default on Docker's part and a careless action on the user's part.
Actually, there's no reason why you should limit yourself to just using tags, since something like "my-image:2022-02-18" might be accidentally overwritten unless your repo specifically prevents this from being allowed. If you want, you can actually run images by their hashes, for example, Harbor makes this easy to do by letting you copy those values from their UI, though you can also do so manually.
For example, let's say that we have two Dockerfiles:
# testA.Dockerfile
FROM alpine:some-very-specific-version
RUN mkdir /test && echo "A" > /test/file
CMD cat/test/file
# testB.Dockerfile
FROM alpine:some-very-specific-version
RUN mkdir /test && echo "B" > /test/file
CMD cat/test/file
If we use just tags to refer to the images, we can eventually have them be overriden, which can be problematic:
# Example of using version tags, possibly problematic
docker build -t test-a -f testA.Dockerfile .
docker run --rm test-a
docker build -t test-a -f testB.Dockerfile .
docker run --rm test-a
In the second case we get the "B" output even though the tag is "test-a" because of a typo, user error or something else. Yet, we can also use hashes:
# Example of using hashes, more dependable
docker build -t test-a -f testA.Dockerfile .
docker image inspect test-a | grep "Id"
docker run --rm "sha256:93ee9f8e3b373940e04411a370a909b586e2ef882eef937ca4d9e44083cece7c"
docker build -t test-a -f testB.Dockerfile .
docker image inspect test-a | grep "Id"
docker run --rm "sha256:8dd9ba5f1544c327b55cbb75f314cea629cfb6bbfd563fe41f40e742e51348e2"
docker build -t test-a -f testA.Dockerfile .
docker image inspect test-a | grep "Id"
docker run --rm "sha256:93ee9f8e3b373940e04411a370a909b586e2ef882eef937ca4d9e44083cece7c"
Here we see that if your underlying build is reproducible, then the resulting image hash for the same container will be stable. Furthermore, someone overwriting the test-a tag didn't break you being able to run the first correctly built image because the tags are just convenience, so you'll be able to run the previous one.
Of course, that loops back to the reproducible build discussion if you care about hashes matching up, rather than just tags not being overwritten.