Will Nix Overtake Docker?
blog.replit.com
blog.replit.com
There's a blog post that goes around from time to time about how a company have three risk tokens to allocate per project on non-boring technologies. Nix seriously needs all three. It's the only technology I've ever vetoed at a startup because I've seen the hell hole it can become - perhaps not for the DevOps engineers who know it, but the team who have to suddenly work within the resulting environment.
And I mean funny. I suspect it is different mindsets. And I personally like that both seem to be thriving.
Again, though, I am glad both are thriving. Competition of implementation is... not that compelling to me. Competition of approach, is amazing.
I found Nix way easier, but the documentation is very... concise.
Once you factor in the efforts required in the long term to mitigate a decade of bundling gigabytes of applications and libraries it's a huge "dev adventure"
The way I see it rampantly (ab)used is as a shortcut to get some software up and running by leveraging a public image and passing tech debt for some component of one's system onto the maintainer of the Docker image, then cobbling together multistage builds from those and microservice architectures to try and support this tech debt model. Sometimes it works, many times it breaks, often it turns into complete and utter nightmares to deal with.
"Amazing Andy got this fantastically complex system up and running in a week all by their self way under time and budget and it works. Now I just want to add this feature or modify this one thing and you're telling me that's going to take how long?" Yea, I've seen this more times than I care to admit.
That's not to say that those technologies don't have good use cases in particular circumstances, it's just that you as an IC probably don't have strong incentives to care about where the project will be in 5-10 years when you will have left for another company in 2-3. A lot of accidental complexity is an unavoidable reality when you have people who put their own careers ahead of most other concerns.
Personally, you would have to pry my Bitnami images out of my cold dead hands.. there is just no way my team of 2 can do anywhere near as good.
This is like saying "just wear a mask": it's not enough.
You rely on what other people are doing now and what they've done in the past.
This is an ecosystem problem, not an an individual problem.
And learning how to manage that mapping was a heck of a time sink.
Or have we reached the stage where folks have secrets management for containers fully orchestrated at a personal user level?
I'm sure if everyone was willing to put in weeks/months of effort it'll be as fun to use as Haskell, but Nix isn't the thing I do so I need something simple - docker/docker-compose works perfectly well for that.
So I agree with some parts of your criticism, on the other hand if Nix is be used to do the sensible subset of "CI servers, AWS deployments, build servers, testing, linting, dev package management, dev system environments, and more are", that would be great.
And what that subset is depends heavily on the given circumstances.
For me, being able to derive the "CI servers, AWS deployments, build servers, testing, linting, dev package management, dev system environments" things from a single source of truth, actually does sell Nix pretty nicely.
When approaching a complex, multi-component source repository, with the requirement for dev-environments, CI builds and generation of production ready Docker-images, a careful and not over-eager Nix build, seems a sensible choice, given that the layered nature of Dockerfiles and docker-compose obscures the DAG nature of built artifacts and dependencies. Nix also doesn't build anything by itself, it merely invokes low-level build tools in isolated environments that only contain the specified dependencies.
Sure, when using Nix one is forced to explicitly state the dependencies of each (sub-component-) build-step, that results in more code than a bunch of RUN ... calls in Dockerfiles. Both approaches have their sweetspots.
An investment into learning Nix is done once. And you are completely right, that refactoring to a Nix based build takes weeks in a serious legacy software project. I wonder myself, if this will be worth it. Currently, I think that might be the case, and that part of the weeks put into the build are not due to Nix and would have been necessary for Docker-based builds, too, and also one can do a lot of stuff much easier with Nix, which leads to "feature-creep" like "oh let me add this preconfigured vim/emacs/vs-code into the build env" that one would probably not do if it weren't so easy to customize everything with overlays and overrides.
But that is a good thing, and it is much better to have a capable tool and critical discussions with colleagues to limit the usage of that tool, than the other way around.
Heck, I remeber when we switched to a Maven build, and had a build with all bells and whistles. That took weeks, too, and all the generated artifacts, like source code documentation sites, were probably a waste if time to implement.
I am not sure if that proves or disproves powerful, declarative and modular build systems.
Dockerfiles and docker-compose.yamls have a learning curve too, but more importantly, if you have to invest more time per build maintenance than with a Nix based build, it is only a matter time until that costs more than the nix approach.
* When you modify your local nix file, there's only a couple things you need to change. It stays small. You can keep track of all these changes because they're in your head.
* The company needs a lot of little changes here and there so they build up. Foobar needs rooster v1,2 while Barfoom needs rooster v0,5. A lot different than managaging a users config. No longer possible to squeeze all the details into one brain.
This isn't to say Nix would be bad at handling any of these things. But I would agree with the OP. I have trouble teaching new devs how APT and shell work. Couldn't even imagine trying to explain Nix syntax to them.
The more Nix is used for, the more likely a dev will have to touch it. And teaching someone who doesn't care Nix is like teaching someone who doesn't care about Makefiles / Git. Doesn't work. They just get mad and say it's too complicated.
The trouble is, it's more significant to consider what the pain is in the worst case.
e.g. Two things which count against Nix: With stuff like Docker, I can get away with not really understanding what's going on, and have a quick + dirty fix. And with Nix, the community is smaller, so it's less likely you'll find an answer to the problem you're having right now.
I worked at a company where the DevOps team used Nix for the production/staging. For local development (and ephemeral development deployments), the dev team came up with a docker-compose setup. -- That said, there was at least one case where the devs contributed to the Nix stuff by way of copy-pasting to setup a new deployment.
I had hopes in the back of my head that "maybe it'll get better/more ergonomic in the next few years".
It's just as easy to make a mistake with git today as it was however many years ago; git hasn't fundamentally changed in ways that make it easier. Git still more/less requires you to have a good understanding of what's going on in order to be comfortable using it.
But, since use of git is now widespread, it's less of an issue. And the git CLI has seen some UX improvements.
Nix is very weird. I'm sure there are some ways its UX could be nicer; but to some extent, doing things in a strict/pure way is always going to have friction if the tools/environments don't easily support that.
Pro tip from an actual pro :
git became significantly easier for me once I decided
1. to just use a good comfortable gui (at least one tui also look good) for anything beyond commit and push. (maybe not everything can be done from your gui of choice but at least you get a good overview of the situation before you dive in with the cli.)
2. and to just stick to the basics. (And when you need to help someone else who didn't, take it carefully even if that means you don't look like a wizard.)
In fact even working on the command line feels easier once I had worked in a good gui for a while.
Don't believe experts who claim that you need to study vim and stick to the git cli to "get it".
But of course: if cli is your thing, use it, just stop writing blog posts that claiming it is the only true way.
I do agree with you that some workflows are just easier with a GUI, since I used to use TortoiseSVN and it was much nicer for diffing two commits than the CLI is. But I haven't really dug into git GUIs.
SourceTree: https://www.sourcetreeapp.com/
Windows and Mac. Free. Feels sluggish, but is also really dependable, the graph view is lovely and it covers most of the common things that you want to do - also, staging/discarding chunks or even individual lines of code is lovely. Oh, and the Git LFS integration, and creating patches is also really easy. And it gives you the underlying Git commands it uses, in case you care about that.
GitKraken: https://www.gitkraken.com/
Windows, Mac and Linux. May need commercial license. Feels like a step up from SourceTree, but i find that using this for commercial needs is a no go. If that's not an issue, however, it has a good UI, is nice to work with and just generally doesn't have anything i'd object to. IIRC it saved my hide years back by letting me do a ctrl+z for a repo after accidentally forcing to the wrong remote, so that i could fix what i had done (memory might fail me, was years ago), just generally feels intuitive like that.
Git Cola: https://git-cola.github.io/
Windows, Mac and Linux. Free and open source. Perhaps one of the more basic interfaces, but as far as free software goes, it does what it sets out to do, and does it well. I use this on Linux, whenever i want to have that visual feedback about the state of the repo/staging area or just don't feel like using the CLI.
TortoiseGit: https://tortoisegit.org/
Windows only. Free. Recommending this just because you mentioned TortoiseSVN. If you just want a similar workflow, this is perhaps your best option. Honestly, there is definitely some merit to having a nice file system integration, i rather enjoyed that with SVN.
Whatever your IDE has built in: look at your IDE
On any platform that your IDE runs on. Same licensing as your IDE. Some people just shop around for an IDE that they enjoy and then just use whatever VCS workflows that they provide. I'd say that VS Code with some plugins is really nice, though others swear by JetBrains' IDEs, whereas others are fine with even just NetBeans or Eclipse (Java example, you can replace that with Visual Studio or whatever). If you're working within a particular stack/IDE, that's not too bad of an idea.
The CLI: https://git-scm.com/
Windows, Mac and Linux. Free and open source. You'll probably want to know a bit of the CLI anyways, just in case. Personally, i'm still way too used to using a GUI since dealing with branches and change sets just feels like something that's more easy when visual, but the CLI has occasionally helped me out nonetheless.
Actually, here's a useful list of some of the Git GUIs: https://git-scm.com/downloads/guis
For example, did you know that there are some simple GUI tools already built in, git-gui and gitk?
At times I have used ungit or git extensions (which, despite its name contains a full desktop application.
Today I use VS Code with a combination of Git Branch for visualization and Git Lens for the rest. Git Lens might need some configuration (I rarely use all the panes, but I use the interactive rebase tool from it as well as some annotationn features. For the visual rebase tool to work I had to configure VS Code as my git editor, but that is how I like it anyway.)
Again: try a few, find one that makes sense for you.
Jetbrains tools for example are generally good, liked by many and well though I understand, but still the git visualization (and a couple of other things) consistently manages to confuse me.
GUI vs CLI shouldn't be about which is a less confusing way of using git.
(Though, yes, magit is excellent, and there are very few tools which come close).
When something goes wrong I just bork the whole repo and clone it again, then manually merge the last set of saved changes.
In some bad days I even miss Clearcase.
Easier? Who needs that? Soon then you will have common unlearned folk and peasants trying to use git. </snark>
They had the super obtuse git reset, that was four different things bolted together, so they fixed it by adding git restore, that does slightly different things, but you still need both...
Nix (and Haskell) has its warts, and undoubtedly a new system would avoid them (compatibility needs make some changes very challenging), but the fundamental difficulty remains because it is fundamentally different and solving a truly difficult problem set.
> I had hopes in the back of my head that "maybe it'll get better/more ergonomic in the next few years".
I feel much the same way about wanting to run something like FreeBSD and having it just work, as opposed to running into weirdness because of the driver situation, with which GNU/Linux seems to be getting better at (even though you sometimes are forced to install proprietary ones for optimal experience, should get better in the next decade).
So, might have to wait for a bunch more years, or just pick something else, like OpenBSD, or just run in a set of constraints for having a really predictable and well supported hardware configuration, which isn't always possible. Alas, my off brand Polish netbook will just have to wait before i can (hopefully) run BSD on it comfortably. Well, short of making the missing pieces of puzzle myself, for which i'd probably also need a decade or so of systems level development experience, as opposed to just web dev and occasionally dabbling in lower level stuff to mediocre success. Of course, by then the netbook itself might not be relevant, so who knows.
I also feel much the same way about GNU/Hurd - a project that is conceptually interesting, but isn't yet quite stable, even though apparently you can get Debian for it: https://www.gnu.org/software/hurd/
Now, i don't have almost any experience with it, apart from reading about it, but some people tried figuring out when it could be released based on the bug reports and how quickly they were being addressed, and the number that they came up with was around 2070 or so.
In summary, there are probably projects out there, for which their age isn't necessarily related to how usable they are, whereas other pieces of software will have never truly achieved that stability in the first place. Not all old software is good (edit: at least not for certain use cases).
Of course, there are exceptions, for example, you can look at Apache2/httpd: it is regarded as old and dated for the most part, however just recently an update was released, which added mod_md. It now lets you get Let's Encrypt certificates without external tools (like Certbot), in some ways setting it ahead of Nginx: https://httpd.apache.org/docs/2.4/mod/mod_md.html Not all old software is always boring.
Same for Docker and any other tools. If developers use tool A for use case X, instead of tool B, then maybe there are some very good reasons for this widespread usage? That's also probably the answer to this debate - regardless of their conceptual/technical benefits, the usability will probably decide which tool will win in the long term.
I also submit that to understand why that happened, one needs to consider the context at the time that the decision was made:
http://www.h-online.com/open/features/GNU-HURD-Altered-visio...
http://www.groklaw.net/article.php?story=20050727225542530
« RMS was a very strong believer -- wrongly, I think -- in a very greedy-algorithm approach to code reuse issues. My first choice was to take the BSD 4.4-Lite release and make a kernel. I knew the code, I knew how to do it. It is now perfectly obvious to me that this would have succeeded splendidly and the world would be a very different place today.
RMS wanted to work together with people from Berkeley on such an effort. Some of them were interested, but some seem to have been deliberately dragging their feet: and the reason now seems to be that they had the goal of spinning off BSDI. A GNU based on 4.4-Lite would undercut BSDI.
So RMS said to himself, "Mach is a working kernel, 4.4-Lite is only partial, we will go with Mach." It was a decision which I strongly opposed. But ultimately it was not my decision to make, and I made the best go I could at working with Mach and doing something new from that standpoint.
This was all way before Linux; we're talking 1991 or so. » -- Friar Thomas Bushnell
They looked at BSD. The BSD people were not sure, so RMS decided on another path.
If GNU had picked the BSD kernel, there could have been a working Free xNix before Linux and things would have been very different.
Secondly, I think it's important when discussing microkernels and microkernel OSes to consider more than the most famous one: Mac OS X.
Xnu is based on Mach, but it's not a pure microkernel: its Xnu kernel contains a large, in-kernel "Unix server" derived from BSD code. This was done for performance reasons – remember, macOS is Mac OS X is NeXTstep, written for a 25MHz 68040 in around 1987-1988.
There are better examples. QNX is probably the best: a working, true-microkernel, Unix-like OS, dating from 1982. At one point shared-source but not any longer.
There is also Minix 3, which is a different OS from Minix 1 & 2, the OS that inspired Linux and upon which Linux was initially bootstrapped.
Minix 3 is still quite limited: no SMP, some missing APIs etc. But QNX proves that a true microkernel, on generic hardware such as x86 and ARM, can support SMP and so on.
Thanks for sharing
this one's very true. Every time I try to build something in Haskell on my laptop it feels like we're moving closer to the heat death of the universe. Is there some good read on how/why Haskell compilation times are so long compared to some other languages?
It seems comparable to what I've noticed with Rust or C, and pretty fast compared to some medium/large C++ codebases I've built.
I'm not really sure what workflows people are using where this is a problem, so this may be less of a pain point for me than it is for you. Personally I build Haskell projects once to pull in the dependencies, then use ghcid to get ~instantaneous typechecking on changes I make to the codebase.
So… you're saying your laptop is super cool? Because the heat death of the universe is when thermodynamic energy is equally distributed everywhere, which, given the large space of the universe, means really cold.
Here's a fun game. Have you ever played Follow the Energy? For example, depressing keys on your keyboard takes energy. Where does that energy come from? Well, the work performed by your fingers of course! But where does that energy come from? Well, the muscles in your fingers, of course! But where does that come from? Well, your food! But what about that? Well, your food's food! That? Eventually plants. That? The sun! That? Nuclear fusion. That? Gravitational potential! That? Etc...
But here's the funny thing. In this image, it kind of seems like energy gets "used up". The sun provides energy to the earth via solar radiation; the plants consume this energy; animals eat the plants, obtaining their energy; etc. However, energy is conserved. What gives?
Better yet, if the earth were not radiating just as much energy as it received, it should be heating up. However, the earth-atmosphere system is mostly constant temperature! This implies that the total energy flux is zero. If X Watts (Energy/Time) is coming in, then the earth actually radiates out X Watts as well.
So... if the total energy flux is zero, then how does your keyboard key actually get pressed? What gives?
The key is entropy. X Watts of solar radiation impinge upon the earth, but these photons are "hotter" (i.e. higher frequency) on average than those that radiate out. The balance is in numbers. You need more cooler photons to balance the energy of the hotter ones. E=hf; energy (E) is proportional (constant h) to frequency (f), after all.
This means that while energy is conserved, the flow of that energy increases the entropy of the system. In a very real sense, typing on your keyboard happens because of the waste heat generated in the process.
All driving us closer to Heat Death...
It's also interesting to play the "Follow the Energy" game to it's logical conclusion, namely that nearly all of the energy in the Universe (including that which you expend typing on your keyboard) originates from the gravitational potential created in the Big Bang (whatever that is, by the way). This begs the question; how was the entropy of the early Universe to low, that it could increase by such an enormous amount, to produce intelligent beings such as ourselves, typing things on a keyboard while we should be working?
It's really one of the most fundamental questions in cosmology, and one of the (many) reasons why I love physics.
Minor pedantry on top of pedantry. The gravitational potential energy of a collapsing protostar gets you past the activation barrier for nuclear fusion, but isn't itself the source of energy beyond that.
Think of it like lighting campfire using friction. The friction heats up the kindling, but that investment allows you to access the potential chemical energy of the wood. The gravitational potential energy is converted into heat, and that investment allows you to access the potential nuclear energy of the unfused hydrogen.
Nice analogy, btw.
In general, I feel like every language that wasn't made to compile fast like Go, OCaml, Pascal and derivatives is going to be called "slow to compile". There's Java and C# that are kind of a middle-ground, since they emit bytecode for a JIT compiler. So my answer to "why Haskell compilation times are so long compared to some other languages?" would be "because compilation times don't take priority over some other points for Haskell and its users".
That does not mean, that the implementation hasn't been moving towards industry-readiness for a long time.
Don’t get me wrong, I’m completely bought in on the vision of reproducible builds but there’s a long ways to go before it’s usable in real organizations. I’ve heard that some orgs manage it, but I really have no idea how. Maybe some critical mass of people who already know and love Nix (and implicitly packaging obscure dependencies)?
I have never used nix, but from the article the author only concentrated on the fact that docker and nix create reproducible environments, and completely misses the other benefits of containers.
As a devops guy if someone hands me a nix project, how do I deploy that so it is highly available and scales by itself?
With containers I just put it in kubernetes.
We did that at an old job. Basically, Nix built images + K8s manifests + a script to push the images. Our CI job boiled down to `nix-build && ./result/push-images && kubectl apply -f ./result/manifests -R`. This is similar to how NixOS' nixos-rebuild boils down to `nix-build && ./result/activate`.
CUE + BuildKit
I'd love a nix-like docker alternative to be fair but that'd be a massive undertaking.
> Nix built the entire world
You're comparing apples to oranges.
Docker just runs commands. If you want to run commands, you can do that in Nix using e.g. nixpkgs.runCommand.
apt-get just fetches prebuilt binaries. If you want to fetch prebuilt binaries, you can do that in Nix using e.g. nixpkgs.fetchurl.
You can even use runCommand to run apt-get (I do this to use Debian's Chromium package on 32bit NixOS)
In contrast, it sounds like you were using Nix as a build tool, to define your entire OS from scratch (presumably using Nixpkgs/NixOS). In which case apt-get isn't a comparable command; instead, the Debian equivalent would be:
apt-build world
Guess what that does?TFA points out using nix as a reproducible build environment - which it is excellent at. Create a shell.nix in your repo, and every dev uses the same exact tools within the comfort of their own machine/shell. Docker is much more painful for this kind of local dev workflow.
That's not to say it's not a great idea. It's just a huge pain to get to work, and the cost of trying to get a perfectly-working Nix environment is just *not* worth it. In my case, I was working with orchestrating virtual machines, which… well, there's a project called nixops that claims to do this. The thing is it flat-out didn't work half the time (also used python2.7 and I believe one of its dependencies were marked as insecure for a long period of time). I got so frustrated with this "advertised" nixops tool, that had to write my own replacement for nixops, and while it was a fun experience, I was so burnt-out from dealing with Nix and its breaking randomly every ten seconds, I just gave up on my homelab.
If you want any program that doesn't exist for Nix, you can't just use the program's build script. You have to manually make a Nix derivation, and then pray and hope it will actually compile. Want to deploy your Ruby on Rails application on NixOS? Prepare to spend three days trying to set this up, since there's only one other application and the entire process is poorly documented (even for a "regular" Ruby program that isn't Rails).
Without additional work, Nix will never be worth its cost (did I mention the interpreter took forever and sometimes failed on errors in files that had NOTHING to do with yours, leaving you to manually debug each line?). You could spend the days upon days upon days trying to get the damned thing to work for something far more useful instead. Since once you get Nix to work, it will break.
I'm sorry if I offended any Nix users/developers, but the product is just not ready for anything yet IMHO. I just don't have time to deal with it anymore, and I'd rather get on doing something more fun than dealing with a bloated, undocumented system that I can just replace with Docker and get my work done in 5 minutes instead of 5 days.
This is a common (and horrible) issue with dynamic languages that pass functions or blocks of code around. There have been some major improvements to Nix error messages which were included in the last release, and there's also ongoing work to address this through gradual typing.
There was a talk on the latter recently, with some examples that I think make the overall issue pretty clear: https://www.youtube.com/watch?v=B0J-SclpRYE
That's good to hear (and I think I heard about it before). The problem is, there are still lingering issues with Nix, like how long it takes to figure out how to compile a new program, (exceptionally) poor documentation, packages being unmaintained, the nixpkgs repository being a gigantic blackhole that takes forever to eval, etc.
Don't get me wrong. I really like the idea behind Nix. Even with this fix though, I'm still not sure I would enjoy using Nix (since many, many other problems) or giving it another shot because of my emotional response to it that's been caused by burnout trying to wrangle with it.
I'm not sure you would, either, and I won't ask you to give it another shot right now. I understand the feeling. Maybe it's something to revisit after more time than has already passed.
In my view, the reason Docker has all the hype is because I can look at a Dockerfile, and know what's up. In seconds. Sometimes in milliseconds.
It's a user experience thing. Yes, Nix is better for 'technical people that spent the time learning the tool', but Dockerfiles rely almost entirely on existing System knowledge.
Yes, Nix is 'better', but the fact is Docker is 'good enough' and also 'stupid simple' to get started.
Also Docker-Compose, I don't know why people hate on YAML. But it takes that same KISS attitude to build complex systems that can also be used as sanity checks for migrating to things like kubernetes.
Being able to spin up a complex full stack app with one command and a compose file that doesn't take any brain cells to read is worth it's weight in gold.
This is like the 'general case tool' vs 'DSL' debate. If it's easy to use, people will use it.
We've been able to utilize Nix to address both of those issues, and others who may be in a similar scenario might also find Nix to be valuable.
Of course Nix comes with its own set of opinions and complexities but it has been a worthwhile trade-off for us.
The image contains dependencies needed for 50+ languages. This means repls by default are packed with lots of commonly used tools. However, the image is massive, takes a long time to build, and is difficult to deploy.
Unfortunately, slimming the image down is not really an option: people rely on all the tools we provide out of the box.
May I ask why you didn't use something like Ansible to build such a complex image? With appropriate package version pinning (which it's the real crux here) it should work well enough to get a reproducible build.
I understand it would already have been something different from a pure Dockerfile so it's not that fair to compare buuut...
They did; it's called Nix, and they wrote a blog post about it ;)
I wish that docker has the ability to merge multiple parent layers like git, then you can build the gigantic image by just updating single layer.
The only hack the docker can do is multistage-build, however that won't work reliably in some cases such as resolving conflicts.
There is actually the --squash command that you can use during builds, to compress all of the layers: https://docs.docker.com/engine/reference/commandline/build/#...
For example:
$ docker build --squash -t my-image .
In practice it can lead to smaller images, though in my experience, as long as you leverage the existing systems in place efficiently, you end up shuffling around less data.E.g.:
- layer N: whatever the base image needs
- layer N+1: whatever system packages your container needs
- layer N+2: whatever dependencies your application needs
- layer N+3: your application, after it has been built
That way, i recently got a 300 MB Java app delivery down to about a few dozen MB actually being transferred, since nothing in the dependencies or the base image needed to be changed since, it just sent the latest application version, which was stored in the last layer.Also, the above order also helps immensely with Docker build caching. No changes in your pom.xml or whatever file you use for keeping track of dependencies? The cached layers on your CI server can be used, no need to install everything again. No additional packages need to be installed? Cache. That way, you can just rebuild the application and push the new layer to your registry of choice, keeping all of the others present.
Using that sort of instruction ordering makes for faster builds, less network traffic and ergo, faster redeploys.
I even scheduled weekly base image builds and daily builds to have the dependencies ready (though that can largely be done away with by using something like Nexus as a proxy/mirror/cache for the actual dependencies too). It's pretty good.
Edit: actually, i think that i'm reading the parent comment wrong, maybe they just want to update a layer in the middle? I'm not sure. That would be nice too, to be honest, though.
`Dockerfile` is light enough for me to not hate it too much.
For the `docker-compose.yaml` story however, I can offer one reason: when you have so many variants(versions), so many setting options and so many data types (array, object, string etc), it's hard to find references to write one from scratch (have to read multiple documents to get it right). Your knowledge on docker command-line parameters does not translate to `docker-compose.yaml` smoothly(some option changed names, some don't work). And sometimes, some function works differently under docker-compose.
You don't have to jump into the deep end with Nix. If you're happy to just run shell commands (like Dockerfiles provide), then all you need is this:
(import <nixpkgs> {}).runCommand "my-package" {} ''
PUT YOUR BASH CODE HERE
''No matter what the format Nix script look like, it's still a script language designed to address something that has already been addressed (or can be addressed with light expansions). The very idea of "Hey let's build this whole new thing that does this specific old task a little bit better at the cost of learning many new concepts (and making many mistakes)" is not good at the core.
I would rather say, if the dudes there really wants to create a new language, fine, but at least make it big. By that, I mean don't just try to build a tool that preforms the old task a little bit better (at cost of learning), make a tool that does new things (in other words, "enables new possibilities") far better. Perhaps after that, the toolset could become something worth learning for.
(Currently, there are many ways to create reproducible builds. And even if you have reproducible builds, it does not mean the build will reproduce the same runtime result all the time. All factors combine, the benefit you can receive from the toolset is just not great enough at the moment. Hope you understand my point)
You don't seem to have a problem with Dockerfiles, yet Nix was around for a decade before Docker existed. If you don't want people to reinvent things that already work, then your complaint should be directed at Dockerfiles. In fact, you should go and complain at the following projects, which were (a) created after Nix, (b) try to solve some subset of things that Nix can already handle and (c) are strictly worse than Nix (e.g. less secure, not reproducible, not cross-platform, tied to one language, etc.):
- Docker
- NPM
- Puppet
- Ansible
- Salt
- Webpack
- Grunt
- Gulp
- Homebrew
- Pip
- Conda
- Poetry
- Gradle
- Vagrant
- etc.
And with reproducability you move the work from fixing broken builds, to implementing builds.
Of course, I can tag docker images and upload them to an internal registry, but that seems more complex to me, than doing this at the source level with Nix.
I hate it haha
It also builds into the Gradle lifecycle neatly. I don't need a separate tool for building images.
I'm sure writing Maven xml wouldn't be fun though!
Or do you mean it's conceptually the same, just implemented differently? I agree there.
Most of the times this just gives me more questions than answers, like: what does the entrypoint.sh file in this repo do? Only to discover a plethora of shell script for setting up the runtime environment based on different environment variables. Most of the time not aligned with any common standard or with how you generally would setup the application itself.
I think your point is very valid, it has got to be simple and increase productivity instead of impede it. Using something better but getting stuck in the minutia every day is a waste, and not something anybody in senior leadership should ever approve.
For immutable distribution they solve the same problem. But they solve it in fundamentally different ways.
If you go back and read the last 20 years or so of LISA papers, it can be … humbling/frustrating. You can read two papers back to back, separated by 15 years, and they’ll be describing a new solution to the same exact problem that still hasn’t been properly solved. Dependency management has been horribly broken in our industry and we’ve never really managed to address it - until Nix. The Nix LISA paper [1] was a breath of fresh air, it really cut to the core of the problems with modern dependency management and addressed them head on.
Docker declared bankruptcy on dependency management and just resorted to fs snapshots to guarantee bit perfect deployments.
[1] https://edolstra.github.io/pubs/nspfssd-lisa2004-final.pdf
Docker might not be simple; there's a lot of moving parts to manage, some hidden gotchas, and networks are a mess. But it's comparatively easy, and once you bake an image, it's pretty simple. Dockerfiles are basically just sh. Package managers are the usual suspects. Images are easy to distribute. It's very familiar.
Nix is not easy. It's a new syntax to learn, it's a new way of building, it's an entirely new way of thinking about the problem. But in the end, it does simplify packaging in the Rich Hickey sense of the easy/simple dichotomy. No braiding of packages and shared libs. But using Nix is not so simple. There's all kinds of bindings and bodges and bespoke shims to make it all work.
History tends to show that easy+non-simple things beat out simple+non-easy things (devs are lazy). Easy-kinda-simple vs non-easy-kinda-simple-but-long-term-gains? No contest in my opinion.
I think Nix is a beautiful idea but it's an uphill battle.
But yeah. The DX "needs work". which is a nice way of saying, I find it downright painful to use.
Nix vs Docker is like Rust vs JavaScript - you can point out every reason js is terrible and rust is better, but for the common developer looking to get things done, they’ll often gravitate to the tool that gets them the biggest impact with the least upfront investment, even if that tool ends up causing major predicable headaches in the future.
Aside from this one executable there is no relationship between the two projects.
The daemon takes .drv files that list what preconditions a build has (= other .drv files), what build script to run (= a generated Guile script), and what outputs will exist when the .drv file has been processed. It processes these .drv files in an isolated environment (chroot + namespaces) where only the inputs mentioned in the .drv file are made available.
The drv files are not shared among the projects; they are not generated in even superficially similar ways. Guix is not a fork of Nix. "guix-daemon" is a fork of "nix-daemon".
Both are implementations of the same idea: functional package management.
They fulfill similar business functions - allowing you to run the same code on a bunch of dev machines and on prod (modulo modifications for e.g. database storage in Docker's case). Nix people get hung up on the fact that Docker runs containers, but it doesn't really matter that much. Often Docker is the shortest path to getting software running on multiple machines reproducibly.
> I also don't understand what you mean by "bindings"
I am referring to derivations and modules. Both are glue that you have to write for existing software that is already packaged. With Docker you leverage the existing packaging ecosystem like pip or apt. The packages are already written for you, and you can follow the installation instructions from a project repository and they translate seamlessly into Docker.
For example with ML & Python - If you want PyTorch with CUDA support, you can follow the official documentation [0] and basically copy and paste the installation instructions to a Dockerfile RUN statements. If anything breaks you can file an issue on the PyTorch issue tracker which has a wide audience. With Nix you have to write glue on top of the installation yourself, or a maintainer does it with a much smaller code review and support audience. Sometimes the audience is just the author, given that Nix project people commit directly to master frequently and do self-merges of PRs [1]. And there are other hurdles like compiling Python C extensions, which are pervasive.
Another example is with software systems, I guess this would be a Nix module. Here's GitLab: [2] where it was really difficult to translate the services into Nix. But a lot of company internal services can look like GitLab with a mix-mash of odd dependencies and languages. And writing a Dockerfile for this is much easier than Nix, since you can copy from the existing README specifying the Debian or language-specific dependencies. (edit: and if there are conflicts between dependencies of the services they can go into different containers. Getting the benefit of Nix - reproducibility - without the extra effort.)
[0]: https://pytorch.org/get-started/locally/
[1]: https://discourse.nixos.org/t/proposal-require-pr-authors-to...
with import <nixpkgs> {};
runCommand "my-python-package" { buildInputs = [ pythonPackages.pip ]; } ''
cd ${/my/project/dir}
pip install
'' (import <nixpkgs> {}).pythonPackages.callPackage
({ buildPythonPackage, dep1, dep2, dep3, pip }: buildPythonPackage {
pname = "my-package";
version = "123";
propagatedBuildInputs = [ dep1 dep2 dep3 ];
doCheck = true;
src = /my/package/dir;
})
{}
That's how Nixpkgs tends to do things, which has nice features like building each dependency separately, allowing easy overrides, etc. but it requires knowledge of how Nixpkgs orchestrates its Python packages.In contrast, 'runCommand' lets us just run a shell script like 'pip install', which is easier but doesn't have those niceties. Also, depending on the platform, the Nix sandbox may have to be disabled for 'pip install' to work, since Nix tries to prevent network access (I think it's enabled by default on Linux, but not on macOS)
To be clear, are you suggesting that
RUN sudo apt-get update && sudo apt-get -y install ...
is somehow reproducible? I'm asking because I was surprised to see the above as being described as "reproducible" of all things. Splitting that into many different containers would likely exacerbate the reproducibility problem instead of improving it.> With Docker you leverage the existing packaging ecosystem like pip or apt. The packages are already written for you
This is even more true for Nix, which has the largest and most up-to-date package repositories out there[1]. Plus, with Nix, you can easily make a new package based on existing packages with a mere few lines of code if the existing packages doesn't fit your needs. Other package managers besides Guix doesn't offer you that flexibility so you'd have to compile from scratch. That's way more tedious, hard to maintain, and definitely not reproducible.
Any results should be documented by making all data and code available in such a way that the computations can be executed again with identical results.
https://en.wikipedia.org/wiki/Reproducibility
-----
> To be clear, are you suggesting that > RUN sudo apt-get update && sudo apt-get -y install ...
No, you need to pin the dependency versions. With Python this practice is already normalized with requirements.txt or conda yml files. So you would take an existing project and do:
RUN conda env create -f environment.yml
which would likely be copy-pasted from the project README. The yml file specifies version numbers for dependencies. The SAT solver is deterministic. For other languages like C maybe the project didn't specify dependency version. So you need to figure them out when you first get a successful build, then specify their versions in apt. You can specify version numbers in the apt-get install line.Yes, this is reproducible. Definitely good enough for most business use cases. When I say reproducible I do not mean ivory tower math proof reproducible. I just mean that the code will run on the relevant machines they are targeting. As I wrote in my initial comment. And as I defined at the top of this comment.
Also Nix provides a worse experience for pinning dependency versions since it does not have a native concept of version numbers [0]. Instead people have to grep through the Nixpkgs repo to find the correct hash of their dependency version.
> This is even more true for Nix, which has the largest and most up-to-date package repositories out there
No, Docker has the closure (to borrow Nix's terminology) of all of the package managers in that graph. If you add the height of the Debian packages with Pypi and Hackage you already have Nix beat. You can keep adding - cargo, ruby gems, etc all in their native package managers. If Nix were better off then people would be adapting Nix packages to other ecosystems. But the reality is the other way around.
> Plus, with Nix, you can easily make a new package based on existing packages with a mere few lines of code if the existing packages doesn't fit your needs. Other package managers besides Guix doesn't offer you that flexibility so you'd have to compile from scratch
With Nix, you are forced to make new packages based on existing packages. That is not a benefit. Regarding "if the existing packages doesn't fit your needs", compiling from source is not a big deal since Docker caches output artifacts.
Your main argument was that Docker "sufficiently" serves the same goal of reproducibility. I just pointed out how it doesn't come anywhere close. Addressing the core of an argument is far from a "semantic" argument.
> where you say basically everything that is not Nix or Guix is not reproducible
My definition of reproducibility is that you get identical build results every time, which should meet the definition you quoted from Wikipedia. "docker build," which runs arbitrary shell commands with network access, is the farthest thing possible from any sane definition of "reproducible."
> Also Nix provides a worse experience for pinning dependency versions
The exact opposite is true. No other system-level package managers like apt or yum truly supports pinning packages. With apt or yum, packages in a repository snapshot are tightly coupled together since they're all installed into a single shared location. It's not possible to swap out or pin a subset of packages without the risk of breakage.
Nix provides a truly working way to pin packages. Packages are installed into its own isolated location to avoid collisions and dependencies are explicitly specified. This makes it possible to mix packages from stable channels, unstable channels, and even specific git commits of those channels. This can't be done with apt or yum.
Language-level package managers are somewhat more flexible regarding pinning, but still has problems. More on that next.
> No, you need to pin the dependency versions. With Python this practice is already normalized with requirements.txt or conda yml files.
Yet CI builds constantly break because Python dependencies are a moving target. And no, the SAT solver doesn't make the builds deterministic. The fact that you even need a SAT solver just makes it clear that dependency management is getting out of hand and we need better tools.
> If you add the height of the Debian packages with Pypi and Hackage you already have Nix beat. ... If Nix were better off then people would be adapting Nix packages to other ecosystems.
I don't know why you believe Nix and only Nix has to compete with all other package managers combined. You must really dislike it if you can convince yourself that is fair comparison.
But Nix can be used along with other package managers, so I don't see the point here. The only anomaly here are Docker images, that monolith binary blob that doesn't compose well like packages in other package managers.
And speaking of fairness
> or a maintainer does it with a much smaller code review
Where did you get this idea from? Nix has a growing community and Nixpkgs is one of the most active repositories on GitHub. Other package repositories with the possible exception of Homebrew and AUR has a much higher barrier to entry, which would most definitely result in, "smaller code review."
> Nix project people commit directly to master frequently and do self-merges of PRs
Self-merges are nowhere near being unique to Nixpkgs so it's unfair to only call Nixpkgs out for it. And if you count language-specific package repositories like NPM or PyPI, you should assume there is zero code review for most packages.
While regrettably there are self-merges in Nixpkgs, it is definitely in the minority and a lot of those changes are especially trivial stuff. Since Nixpkgs has a vibrant community, things like this tend to get attention and some community members are keeping an eye on it and is quick to bring these instances up. It's also worth noting that the Nix community is especially invested in automated testing compared to other package managers and these are run on PRs that ends up being self-merged.
> With Nix, you are forced to make new packages based on existing packages.
That is 100% FUD.
> "if the existing packages doesn't fit your needs", compiling from source is not a big deal since Docker caches output artifacts.
It is a big deal that you can't reuse code with non-Nix package managers. Docker caching isn't relevant and does nothing to deal with maintainability or reproducibility issues. Our company maintains custom OpenSSL RPMs, and it has been a constant source of pain due to RPM's lack of code reusability. Now we also have to maintain our own version of every single package that relies on our build of OpenSSL, which is a nightmare. This wouldn't have been a problem with Nix.
No, I do not give a single fuck about Nix versus Docker. I have no personal attachment to either. I am just worried that pushing Nix at my company would be some form of professional malpractice given the downsides. I literally have a meeting tomorrow about incorporating Docker into a different team's product. I've used both Docker and Nix before. If Nix would be better for them, I would tell them as much. I'd be fine continuing this discussion we are having, some parts were interesting. But unfortunately you seem incapable of formulating an argument without resorting to personal attacks and condescension. And I cannot tolerate that.
self: super {
fish = super.fish.override {
fishEnvPreinit = sourceBash: sourceBash "${self.nix}/etc/profile.d/nix-daemon.sh";
];
}
This would source the given bash script (using fenv IIRC) at the same point that NixOS fish would load its environment, thus producing the same behavior (notably, setting up all of the various directories prior to running any user code, unlike nix-env.fish that has to try and patch things up after the fact). The downside is that it means you have to recompile fish.[1] https://github.com/jchilders/dotfiles/blob/main/Makefile
> sudo curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/in... | /bin/bash
piping the output of a curl command to sh without first checking the sha256 of the file you just got?
In a similar situation I would not be comfortable without at least getting a specific version of the tool I'm downloading and then hardcoding an hash of its content I computed after manually downloading and inspecting its content.
And if you really want to understand it, Graham Christensen (the contributor of the buildLayeredImage function) wrote a really good blog post on how it works: https://grahamc.com/blog/nix-and-layered-docker-images.
nix being really good at package management is something docker needs to imitate -- out of order apt-get without requiring a re-downloading all the packages, for example, seems like it would shrink most cloud build costs. I guess this is what the article means by trouble 'sharing layers'
docker buildkit (or moby buildx or wherever the branding has settled) is supposed to to improve caching, but creating a simple API for caching that plays nicely with system + language package managers would really move the needle here; reorderable package installs would be the v2
https://nixos.org/manual/nix/stable/#multiple-versions
The Nix and container mindset are very similar in that they refer to all of their dependencies, including down to glibc.
Postgres, for example, would require configuring each version to use a distinct space for storage and configuration if you want to run them concurrently. It's still pretty easy with NixOS, but not as simple as you make it seem.
Edit: Totally granted, figuring out that one line the first time might take 6 hours, but once you know how to do it you're good to go the next time. The documentation could certainly be improved.
I get you could configure different ports, or virtual interfaces, but it sounds like either of those would be outside of the nix tooling.
No, it doesn't solve the TCP port isolation problem. (But Docker doesn't really either. Linux network namespaces should, but nobody bothered to develop tools for that yet.)
I think this doesn't work as well on docker desktop for mac
This separation of concerns is one of things I like about Nix when compared to something like Docker. For instance, if you use the Docker image format for packaging, then you're also forced to buy into its specific sandboxing model. With Nix, you can choose to run applications the way you see fit.
However, Guix has its own container implementation. And this is significantly lighter than Docker (instead of layers, links to /gnu/store) and is root-less. If Guix containers had a runc-compatability layer and better docs/tutorials, it would be hard to go back to Docker/podman.
Could you please elaborate what you mean by "runc-compatability layer"? And what about the docs requires clarification?
(I wrote the original Docker export backend for "guix pack", so I have an interest in improving this feature where necessary.)
I sort of got this idea from runj [0], an attempt to create an OCI compatible runtime for FreeBSD jails.
The main advantage is to use certain OCI-compatible tools (e.g. k8s) with Guix without needing to use Docker.
[0] https://samuel.karp.dev/blog/2021/03/runj-a-new-oci-runtime-...
If you ever need a container with a handful of well-known utils installed, just specify them in the image URL. Positively magical!
It's true that Docker is often abused in very creative ways to do what Nix does, but it still remains a different tool with a different goal in mind.
Whereas Nix makes it rather trivial to compose together the packages you need (eg Rust, NodeJS) in your environment.
And that is a big miss. Being able to describe "now append this layer and all, but only, its file changes from this previous layer" would be pretty epic.
For workstations? ostree is the future, not nix, IMO. Check out Silverblue. Flatpak takes care of the desktop aspect.
NixOS is an interesting attempt at solving the reproducibility problem, but it hasn't been adopted because it's just a stepping stone towards a better solution. It has far too many quirks to hit mainstream, it's too complex, under documented and it's still based upon package management, which is getting obsolete as the Linux world is moving fast towards containerising everything.
Container images still rely on package management. There's no fully containerized future where everything is just `./configure && make && make install`'d all the way up from Linux From Scratch or whatever.
Fedora Silverblue's ostree image is still managed by dnf and RPM underneath, too.
I highly doubt this, Dockerfiles are simpler for a hello world microservice, but they get worse and unmaintainable when you add them lots of them with docker-compose.
>ostree is the future, not nix >flatpak takes care of the desktop aspect
I really hate the approach this approach, it just moves the state from the root system to the user. The root directory is immutable, but you move the whole responsability to Flatpak, which is not even comparable to nix. Meanwhile, in case of Nix, the whole system is reproducible and settings are more and less immutable.
>it's too complex
My whole nix config (with specific configs for vscode, neovim, chromium, wireguard, rust, python, nodejs, c++, go) is less than 600 lines of code, and it's readable. Also I configure most of my open source projects via nix as well as it's pretty easy to share the environment with the other developers. Nix works everywhere, on every linux distro, macOS and even Windows via cygwin or wsl.
>under documented
That's a really good point, nix maintainers didn't care much about documentation, but usability. But it looks like that's changing, they moved docs to mdbook and a team is working specifically on improving the docs
You can enable/disable timers, trigger them manually, see when they last triggered, see when they will next trigger. And probably a bunch of other stuff. They also have individual files so automation can easily add or remove timers. For a power user, systemd timers are much better. But if you just want to quickly add one thing, it probably isn’t worth the effort to learn
You can use, e.g.,
services.cron.enable = true;
services.cron.systemCronJobs = [ ''
*/30 * * * * someuser bash /path/to/some/script/idk.sh
'' ];
or if you really don't want to worry about the Nix syntax for a list of strings, and possible escaping issues, you can just create a crontab file in /etc/nixos next to configuration.nix and write services.cron.cronFiles = [
./crontab
];Also given that a blog post posted today is already sort-of out of date [1] when it comes to Nix, it is going to take a while. (Not that it really matters for the context of this blog post).
[1] Despite being an 'experimental' feature, the future of Nix is Flakes which are most simply a function definition (inputs & outputs) with the inputs pinned via hashes.
If "aggressive" means fully, then why doesn't that fix the issue?
I can solve this by maintaining my own Docker registry, and my own NPM registry, but that's more work that just fully specifying versions in a configuration file.
As for auditing changes, well most people don't. They update their dependencies and run their tests and if the tests pass, ship it! Most companies don't have a team auditing every single dependency that's pulled in, much less every update after a dependency has been approved. They simply trust the authors of Redis not to screw them.
It's great if you do, I'm certainly not arguing against it, but it's far from the norm.
docker pull redis@sha256:619af14d3a95c30759a1978da1b2ce375504f1af70ff9eea2a8e35febc45d747Do people really build images this way? It sounds completely insane to pull packages like that randomly from the Internet.
Do you work in an environment that maintains custom copies of every dependency in company managed repos? If so, my experience suggests your the outlier, not the people running apt, npm, etc inside their Dockerfiles.
It was really nice doing a full image rebuild and knowing the only thing that changed it was you explicitly changed.
Super easily honestly, one of those things that we never even think about until someone upstream does something that would have screwed us anyway, like republishing a version number
Additionally, docker builds have free access to the network to do anything it would like. Nix goes to great lengths to sandbox builds and limit network access. Anything accessed from a network requires a pinned sha 256 hash to ensure the remote data hasn't changed. (https://nixos.wiki/wiki/Nix#Sandboxing)
It appears that with the proper package manager support, Docker would be fine?
I come from a hardware background and seem to be a lot more paranoid than most software folks. I would struggle to trust a build where so much is not pinned.
Guess what? If has paid off in terms of personal efficiency - and I can make a good living doing it to boot with some effort.
If you want to aim for the mountaintop, don't let the weight of cynical complainers hold you back. Remember: It takes guts to be amazing.
That being said Nix even with its usability issues works better for reproducible development environments than anything else (including Docker) ATM. Therefore in my view either Nix or something very similar will be the solution for this and replace Docker (some people run builds using Docker containers) for this use case.
https://nix.dev/tutorials/towards-reproducibility-pinning-ni...
I have no experience with Nix. But a couple of red flags jump out of this thread for me are that "it's complicated", Haskell is somehow involved, and it is vaguely suggested that this is somehow similar to Docker. Which is clearly not the case.
When it comes to putting stuff in a docker container, I guess you could use Nix. But why would you? It makes about as much sense as using Ansible or Puppet for that.
Nothing against Haskell, but it evokes an image that might be a bit harsh to some but probably rings true to many: the wrong people getting excited for the wrong kind of reasons. I'm talking over-engineering here. People getting overly excited and creating a mess of hard to understand code that becomes a burden for whomever has to train up to maintain that code. People wielding hammers looking for ever more nails to wack.
I've unceremoniously ditched multiple configuration languages over the years. Usually it feels good getting rid of all the over engineered crap when you realize you don't need most of it anymore. Of course the flip side is that what you replace it with might end up being similar. Been there and done that.
However, I seem to only need a few lines of Dockerfile to replace what used to be a convoluted mess of puppet or ansible scripts to provision a thing that runs our thing. No longer needed. No more obsessing on how to, for example, get NTP tell the time to a server and why that somehow requires wrapping your head around a 600 line puppet module that does god knows what. Not a thing anymore.
Nix sounds more like that than like Docker. I used to know people that actually used puppet to setup their laptop. Nix might be a better product for that. But I'm looking to minimize the need for that entirely. Dockerized development environments are great for that. A laptop with a browser running vs code is all you need these days. People are using freaking ipads to do development even.
In terms of Nix versus Docker, they're completely different levels of abstraction and solve completely different problems. Docker is (among other things... it does a lot of things) an abstraction for reproducing network services on arbitrary platforms. Nix is an abstraction for installing and setting up files.
> One is a container deployment toolkit and the other is a package and configuration manager.
My reading, based on the mapping from the arrangement of the 2 words Nix and Docker, is that Nix is a "container deployment toolkit" and docker "package and configuration manager".
Of course, this interpretation is wrong.
Further, even if applying container deployment toolkit as a description to docker, it still misses a core part of docker, I.e., docker is also a container image building tool kit. The building part and the deployment are for different steps with seemingly equal importance.
[1] https://www.freedesktop.org/software/systemd/man/systemd-nsp...
But Docker does much more than that. People use it especially to isolate runing software and deploy microservices.
A couple of comparisons are similar: with Terraform (or CloudFormation etc.), you put in a lot of effort up front in order to reduce maintenance effort later. You could manually go through and setup a VM instance or two; but with Terraform, you have a declaration in code of what the system should be.
I think another comparison is: Vim or Emacs are more difficult to use compared to using VSCode. In terms of DX, there are advantages to Emacs over VSCode. If modal editing seems to make sense, it's probably worth looking at vim. But, if you just want to get the job done right now and not fuss about learning an unfamiliar tool, VSCode is surely a better choice.
- is fast (faster than Homebrew or Docker)
- is multi-user (don't need root privileges to install software)
- lets you try software without permanently installing it
- gives you fast, reliable undo without requiring a special filesystem
- lets you automatically (re)produce a setup that never drifts from its official definition
- can safely perform upgrades and configuration changes without thinking about what has been done to the system or environment in the past
- has tons and tons of software already packaged for it at this point, which you can just use without any special effortIf your problem is that you want to run unrelated instance of postgres... you don't really have a problem to begin with. Either use docker run to run your postgres image on different ports with different volumes, or just make a docker-compose YAML file with a bunch of postgres services. It's not like you have to have a single one.
For now you can cross-compile to Windows using Nix and you can run Nix in WSL
I see that it could be useful, but it completely turns me down immediately.
What do you dislike about the language?
* Primitive values (strings, numbers, paths, booleans, null)
* Lists and sets
* Variables
* Functions
* Conditionals
* Assertions
* Arithmetic operators
And that's all there is. For people familiar with programming, it should only take around 10 minutes or so to grasp the syntax. It would take much, much longer for commonly used programming languages like C, C++, Javascript, Python, Ruby, Perl, ... you name it.
The official docs does a decent job at explaining the syntax[1]. I didn't have any experience with functional languages prior, but I didn't have much problem grasping the syntax once I've read through the documentation.
[1]: https://nixos.org/manual/nix/stable/#ch-expression-language
Looking at the page you link for example: https://nixos.org/manual/nix/stable/expressions/expression-s...
<<{ stdenv, fetchurl, perl }:>>
<< Nix functions generally have the form { x, y, ..., z }: e where x, y, etc. are the names of the expected arguments, and where e is the body of the function. >>
Strange, but let's say ok. But then, in the example, where does the function end?
Then, <<"So we have to build a package. Building something from other stuff is called a derivation in Nix (as opposed to sources, which are built by humans instead of computers). >>
Looking at that, I say whaaaattt? "derivation" does not mean anything obvious to anyone used to build packages. And then, as the subtitle said, did they decide to use a weird name just to confuse everyone for the pleasure?
Then: << A set is just a list of key/value pairs where each key is a string and each value is an arbitrary Nix expression. They take the general form { name1 = expr1; ... nameN = exprN; }. >>
So, looking at the code, from far, function, sets, everything looks mixup ...
> Looking at that, I say whaaaattt? "derivation" does not mean anything obvious to anyone used to build packages. And then, as the subtitle said, did they decide to use a weird name just to confuse everyone for the pleasure?
The same kind of reaction can be made to any programming concept introduced in an introductory material. I don't think it's fair to ridicule Nix for defining its own technical terms, especially when the writing you referred to explains what it is. It is somewhat light on details, but you can't possibly expect an introductory section to explain it all at once. It should be enough to keep you going.
But to answer your question, a derivation is the low-level build instruction that Nix's package builder can parse and build packages out of. You use the Nix language to convert high level package definitions to Nix derivations before feeding it to the package builders.
[1] https://lobste.rs/s/sizjqf/migrating_from_docker_podman#c_op...
I think that's a mistake, but it's true that Nixpkgs suffers in some places from missing or overlapping abstractions.
Long answer: nooooooooooooooo.