I mean, that's exactly what a Dockerfile is for. I don't know of anyone seriously using Docker that isn't using Dockerfiles exclusively. I only know of a single time when it's valuable to "commit" a new image (recovering logs from a stopped container).
None of which is to detract from Nix. Nix+Docker is a powerful combination. It takes Docker's declarative nature all the way down to the compiler used to build the bits placed in the container.
The big difference is that nothing about Dockerfiles implies that the processes they perform to build an image are deterministic or repeatable. Will a build step that runs `curl https://github.com/something/whatever` do the same thing in six months that it does today? Docker doesn't help with that at all. Nix improves determinism by (almost) guaranteeing that if you build the same nix expression six months from now, you'll get exactly the same dependencies, all the way down to glibc. Either that or the build will just fail, if remote dependencies aren't downloadable anymore, which is always tons of fun.
Finally someone understands what really annoys me when I say that docker isn't 100% reproducible if you aren't using version pinning or something similar.
If you have 2 developers, and one of them does a build the next day, you could have them with two different versions of a package when the version went up.
That isn't even the bad part - the bad part is that give some big complicated docker image (or any build in general!), you really have no practical way of knowing what's different.
Ex-Gentoo dev here. It is not the same. Gentoo emerge runs in place, and you can definitely break your system with a broken build.
NixOS on the other hand, builds everything in sandboxes that only expose the requested dependencies. Builds are almost 100% deterministic. The cherry on top is that your system installation is simply a package consisting of all other packages and configuration symlinked together, and you replace your entire system in one go (atomically, by writing a symlink).
If the build fails at any point along the chain, you get an error and your system remains unchanged. You can totally switch from one major release to the next (and back) without hassle.
It's been a LONG time, but when you build gentoo packages you can save the builds, right? Then if you bring up identical servers, you can just install from precompiled packages.
You're not wrong, but Docker comes at it from a different angle; Docker expects you to be handing around tagged images, to solve a similar set (but not the same set!) of problems that reproducible builds solve.
Ideally, I want _both_ of them: tagged Docker images being sent between environments (with `docker run -e SOME_ENV=testing imagename` for changing the internal config), but reproducible builds in my Dockerfile. I wonder if Nix can be used to achieve that last part?
You solve it by signing the image. Sometimes you just won't be able to get a completely reproducible build processes that's fully deterministic, so Nix cannot fix this problem entirely. Additionally, sometimes you just don't have time, or experience to take another program/tool you didn't write and package it up such that it never downloads things from the internet.
It's a hard problem to solve, and Nix helps a lot, but it's not going to fix all the problems, which is why we should care more about trusting the packager to package something relatively reproducible and sign it so that we it can be vouched for.
Yes, you can do this. There is a utility "nix-docker" that will convert a Nix configuration file into a BusyBox Docker image (see e.g. http://zef.me/blog/6049/nix-docker)
In practice, one can check the Dockerfile lineage of a given Docker image and assess the quality of the commands. Good practices are to use package managers with explicit versions, for example "apt-get install subversion-tools=1.3.2-5~bpo1". Or, if you so desire, just pipe NixOS outputs into Docker, as somebody else in this thread mentioned.
Q: "What does building a a Docker image using Nix give you over creating a regular Dockerfile to build a Docker image?"
A:
* Better abstraction (e.g. the example of a function that produces docker images)
* The Hydra build/CI server obviates the need for paying for (or administering a self hosted) docker registry, and avoids the imperative push and pull model. Because a docker image is just another Nix package, you get distributed building, caching and signing for free.
* Because Nix caches intermediate packages builds, building a Docker image via Nix will likely be faster than letting Docker do it.
* Determinism. With Docker, you're not guaranteed that you'll build the same image across two machines (imagine the state of package repositories changing -- it's trivial to find different versions of packages across two builds of the same Dockerfile). With Nix, you're guaranteed that you have the same determinism that any other Nix package has (e.g. everything builds in a chroot without network access (unless you provide a hash of the result, for e.g. tarball downloads))
---
IMO, NixOS almost subsumes Docker. Where Docker gives you a way to guarantee that the contents of an image will be the same across two machines, it does little to ensure that building that image from a given Dockerfile is a deterministic. One of Docker's neat tricks is using layers to try to save on disk util -- but even then, Nix beats Docker; if you start two different containers using Nix packages, the common packages are shared across both containers, whereas two different Docker images with an uncommon base would not share the common files.
Docker mostly looks like someone set out to answer two questions:
1. How can we work around all of the problems inherent in conventional package management so we can have a smidgen of determinism?
2. How can we have a relatively nice/cohesive UI around launching/inspecting containers and managing networking/bind-mounts?
#1 can be side-stepped entirely with a package manager that doesn't cause all of those problems in the first place (Nix/Guix).
#2 is still quite useful, but would have been better served as layering on top of something like Nix or Guix (not that I really approve of the "wannabe systemd" daemon approach that Docker employs (all while being, ironically, rather difficult to use with systemd: https://lwn.net/Articles/676831/ )).
I sort of agree, but I also think there's no reason to view Docker commits any differently to Git commits.
Are you screwed if you lose a working .git project, or its maintainer? Well, yeah. But we don't actively worry about that happening all that much because we routinely take precautions like distributing it across developer's machines and servers.
Maybe a commit does break, but that's why we didn't just overwrite the previous image.
But also:
> I only know of a single time when it's valuable to
> "commit" a new image (recovering logs from a stopped
> container)
It doesn't have anything to do with a commit breaking anything. It has to do with reproducability. As others have mentioned, a Dockerfile isn't perfect (I'd argue Dockerfile+Nix is pretty close) but at least you don't have to ask "Oh god, what did OJ Ford run manually before commiting the image we use in Prod." That's truly horrific and simply isn't a problem if you use a Dockerfile.
>Not everything's open source.
I don't know what that means. Whether the source is closed or not has zero impact on the use-cases I'm discussing for Docker. Even if the source of the base layer isn't available, it doesn't stop you from using that base layer in a new Dockerfile, at all.
None of which is to detract from Nix. Nix+Docker is a powerful combination. It takes Docker's declarative nature all the way down to the compiler used to build the bits placed in the container.