Interesting viewpoint! What are your arguments for this being a better solution than containerization?
Interesting viewpoint! What are your arguments for this being a better solution than containerization?
- Nix packages can compose in arbitrary ways, containers can't
- Nix can get much more consistent and granular caching
- once an image is built it's reproducible, but the Dockerfile to run it probably isn't—unless it was written very, very carefully to pin everything—so what happens if you need to update one or two packages in an image?
- not 100% sure here, but it seems that lightweight sandboxing like Nix shells or virtualenvs are a lot more convenient for local development and tooling integration
That said, containers might make more sense for, say, deploying and sandboxing services—that's just a different problem from reproducibly managing dependencies and development environments. Nix can build container images, which lets you get the best of both worlds.
$ VER=$(dpkg -s alsa-oss | grep -m1 '^Version: ' | sed -e 's/^Version: //g')
$ cat > Dockerfile <<EOF
FROM ubuntu:21.04
RUN apt-get update && apt-get install -y alsa-oss=$VER
EOF
$ cat Dockerfile
FROM ubuntu:21.04
RUN apt-get install alsa-oss=1.1.8-1
$ docker build -t testimg .
$ docker run --rm -it testimg dpkg -s alsa-oss | grep ^Version:
Version: 1.1.8-1
That's a complicated example. All you need to do is get a working system, specify the base image tag, run dpkg -l and write down all the versions, then pass them to apt-get install. It's super easy. It's much more complicated to do something like download a static Go app from a specific URL, import a GPG key, validate the key, verify the checksum, etc.This would freeze all the packages on the system into a file for use in a Docker container:
$ dpkg -l | awk '{print $2,$3}' | sed -e 's/ /=/g' | tail -n +6 | xargs > packages.txt
$ cat > Dockerfile <<EOF
FROM ubuntu:21.04
COPY packages.txt /packages.txt
RUN apt-get update && apt-get install -y $(cat /packages.txt)
EOF
If you just want to find out the dependencies for a package, use something like apt-cache rdepends alsa-oss and then get the versions and pin them. It's pretty trivial to just read the man pages for dpkg or apt and get what you want done.You commit packages.txt and Dockerfile to a Git repo, and you push your built images to an artifact repository. Test it, validate it, ship it to production. It's all immutable so it doesn't need to be reproduced, you just roll back to the last artifact.
This is not an issue with nix as nix has the ability to build the entire system from source forever in a single command.
But gradually over time as its usage increase and it's extended by more and more even larger applications -- your app will turn into part of the OS. Containerizing your app doesn't help in this case.
Imagine how many services from the OS you are using. Next imagine each one running in a different container and you have to build your app using 100s such containers.