Absolutely. I would ultimately like a container image (docker format or otherwise), containing precisely the files that are needed by the intended service, and nothing else. In particular, the container should not contain unwanted cruft like wget, pip, apt, vi, cp, etc.; and it certainly shouldn't contain a shell (bash/dash/busybox/etc.).
The way docker runs containers is fine (albeit overly-complicated for my tastes, e.g. "loading an image from a registry", compared to something like `kvm -hda myImage.img`)
The way docker's tools build those images is bad. Hence why Nix, Guix, etc. are better for that.
> Small docker image: look into Alpine which comes in at ~5MB. You are basically starting from nothing.
Nope, that is starting from an entire OS. Even a busybox-only image is made dangerous by the existence of a shell, since we have to worry about exploits letting attackers 'shell out' (and from there, inspecting and altering the application binary, not to mention trying to jailbreak or remote-out of the shell to do damage elsewhere, etc.)
> Versioning: both apt and pip allow you to specify a version.
I don't particularly care about versions; I want to specify the SHA hash, so I know if something has changed on the third party server (pypi, ubuntu, or whatever); or whether my connection has been re-routed maliciously; or the download was interrupted/corrupted; or some distant config/setting has changed the resolver's behaviour; and so on.
I also want some way to enforce this, so that no file can exist in the container without being verified against an explicit SHA: either directly, or extracted from an archive with a specified SHA, or checked-out of a particular git commit (which is itself a SHA), or built in a deterministic/reproducible way from components with known SHAs (e.g. a tarball, GCC binary and Makefile, all with known SHAs), etc. I want a fatal error if I forget a SHA.
A system like that would be tolerable, but still an uncomfortable step backwards.
Verifying SHAs is good, but we'd still be running random binaries fetched from a third-party. Unlike apt, pip, etc. Nix gives me the full provenance of everything: I can, at a glance, see whether a particular patch was applied to the GCC that compiled the bash that was used to build my binary; or whatever (admittedly, this is more useful for auditing things like OpenSSL, rather than trusting-trust attacks on GCC).
I can also, with a single command, recreate any of those build environments in a shell, e.g. if I need to test the presence of a vulnerability or bug. As a by-product, I can also use those for development, jumping in to any step along the provenance chain to edit files, run tests, etc.
I can also choose whether or not I want to trust the builder/provider of those binaries, or whether I want to build them myself, and I can choose at what level I want to place that trust; e.g. maybe I trust their GCC, but I want to build the JDK myself. As a by-product, I can also switch out or alter any of those steps, e.g. enabling a GCC flag for a certain build, completely replacing the JDK with another, etc. The Nix language, and the architecture of the Nixpkgs repository, makes this very easy; and Nix itself takes care of rebuilding everything downstream of such changes.
To understand this, I like to think of Nix more like an alternative to Make, rather than apt/dpkg/pip/etc. Those tools are band-aids, created because Make doesn't scale or compose very well. Similarly, Dockerfiles/Chef/Puppet/Ansible/etc. are band-aids created because apt/dpkg/pip/etc. don't scale or compose well. Nix does compose and scale well, so it can be used across that whole spectrum of 'get result FOO by running commands BAR' (we can take it even further with projects like Disnix and NixOps which perform orchestration, but I've personally never used them).
Absolutely. I would ultimately like a container image (docker format or otherwise), containing precisely the files that are needed by the intended service, and nothing else. In particular, the container should not contain unwanted cruft like wget, pip, apt, vi, cp, etc.; and it certainly shouldn't contain a shell (bash/dash/busybox/etc.).
The way docker runs containers is fine (albeit overly-complicated for my tastes, e.g. "loading an image from a registry", compared to something like `kvm -hda myImage.img`)
The way docker's tools build those images is bad. Hence why Nix, Guix, etc. are better for that.
> Small docker image: look into Alpine which comes in at ~5MB. You are basically starting from nothing.
Nope, that is starting from an entire OS. Even a busybox-only image is made dangerous by the existence of a shell, since we have to worry about exploits letting attackers 'shell out' (and from there, inspecting and altering the application binary, not to mention trying to jailbreak or remote-out of the shell to do damage elsewhere, etc.)
> Versioning: both apt and pip allow you to specify a version.
I don't particularly care about versions; I want to specify the SHA hash, so I know if something has changed on the third party server (pypi, ubuntu, or whatever); or whether my connection has been re-routed maliciously; or the download was interrupted/corrupted; or some distant config/setting has changed the resolver's behaviour; and so on.
I also want some way to enforce this, so that no file can exist in the container without being verified against an explicit SHA: either directly, or extracted from an archive with a specified SHA, or checked-out of a particular git commit (which is itself a SHA), or built in a deterministic/reproducible way from components with known SHAs (e.g. a tarball, GCC binary and Makefile, all with known SHAs), etc. I want a fatal error if I forget a SHA.
A system like that would be tolerable, but still an uncomfortable step backwards.
Verifying SHAs is good, but we'd still be running random binaries fetched from a third-party. Unlike apt, pip, etc. Nix gives me the full provenance of everything: I can, at a glance, see whether a particular patch was applied to the GCC that compiled the bash that was used to build my binary; or whatever (admittedly, this is more useful for auditing things like OpenSSL, rather than trusting-trust attacks on GCC).
I can also, with a single command, recreate any of those build environments in a shell, e.g. if I need to test the presence of a vulnerability or bug. As a by-product, I can also use those for development, jumping in to any step along the provenance chain to edit files, run tests, etc.
I can also choose whether or not I want to trust the builder/provider of those binaries, or whether I want to build them myself, and I can choose at what level I want to place that trust; e.g. maybe I trust their GCC, but I want to build the JDK myself. As a by-product, I can also switch out or alter any of those steps, e.g. enabling a GCC flag for a certain build, completely replacing the JDK with another, etc. The Nix language, and the architecture of the Nixpkgs repository, makes this very easy; and Nix itself takes care of rebuilding everything downstream of such changes.
To understand this, I like to think of Nix more like an alternative to Make, rather than apt/dpkg/pip/etc. Those tools are band-aids, created because Make doesn't scale or compose very well. Similarly, Dockerfiles/Chef/Puppet/Ansible/etc. are band-aids created because apt/dpkg/pip/etc. don't scale or compose well. Nix does compose and scale well, so it can be used across that whole spectrum of 'get result FOO by running commands BAR' (we can take it even further with projects like Disnix and NixOps which perform orchestration, but I've personally never used them).