mirror of
https://github.com/NixOS/nix-pills
synced 2024-11-10 13:54:14 +00:00
Pill #1
This commit is contained in:
parent
7768b7e7d6
commit
c596b2114f
3 changed files with 281 additions and 2 deletions
|
@ -1,7 +1,7 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
sources = lib.sourceFilesBySuffices ./. [ ".xml" ];
|
||||
sources = lib.sourceFilesBySuffices ./. [ ".xml" ".txt" ];
|
||||
|
||||
combined = pkgs.runCommand "nix-pills-combined"
|
||||
{
|
||||
|
|
|
@ -4,5 +4,282 @@
|
|||
version="5.0"
|
||||
xml:id="why-you-should-give-it-try">
|
||||
|
||||
<title>why-you-should-give-it-try</title>
|
||||
<title>why you should give it try</title>
|
||||
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
Welcome to the first post of the <link
|
||||
xlink:href="https://nixos.org/nix">Nix</link> in pills series.
|
||||
Nix is a purely functional package manager and deployment
|
||||
system for POSIX. There's a lot of documentation that
|
||||
describes what Nix, <link
|
||||
xlink:href="https://nixos.org/nixos">NixOS</link> and related
|
||||
projects are.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The purpose of this post is to convince you to give Nix a try.
|
||||
Installing NixOS is not required, but sometimes I may refer to
|
||||
NixOS as a real world example of Nix usage for building a whole
|
||||
operating system.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Rationale of pills</title>
|
||||
<para>
|
||||
The <link xlink:href="https://nixos.org/nix/manual/">Nix
|
||||
manual</link>, <link
|
||||
xlink:href="http://nixos.org/docs/papers.html">related
|
||||
papers</link>, <link
|
||||
xlink:href="http://www.infoq.com/articles/configuration-management-with-nix">articles</link>
|
||||
and wiki are excellent in explaining how Nix/NixOS works, how
|
||||
you can use it and the amount of cools thing being done with it,
|
||||
however sometimes you may feel some magic happening behind the
|
||||
scenes hard to grasp in the beginning.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This series aims to complement the missing explanations from the
|
||||
more formal documents.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Follows a description of Nix. Just as pills, I'll try to be as
|
||||
short as possible.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Not being pure functional</title>
|
||||
|
||||
<para>
|
||||
Most, if not all, widely used package managers (<link
|
||||
xlink:href="https://wiki.debian.org/dpkg">dpkg</link>, <link
|
||||
xlink:href="http://www.rpm.org/">rpm</link>, ...) mutate the
|
||||
global state of the system. If a package
|
||||
<literal>foo-1.0</literal> installs a program to
|
||||
<literal>/usr/bin/foo</literal>, you cannot install
|
||||
<literal>foo-1.1</literal> as well, unless you change the
|
||||
installation paths or the binary name.
|
||||
</para>
|
||||
<para>
|
||||
Changing the binary names means breaking possible users of
|
||||
that binary.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Debian for example partially solves the problem with the
|
||||
<link
|
||||
xlink:href="https://wiki.debian.org/DebianAlternatives">alternatives</link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
So in theory it's possible with the current systems to install
|
||||
multiple versions of the same package, in practice it's very
|
||||
painful.
|
||||
</para>
|
||||
<para>
|
||||
Let's say you need an nginx service and also an nginx-openresty
|
||||
service. You have to create a new package that changes all the
|
||||
paths with e.g. an -openresty suffix.
|
||||
</para>
|
||||
<para>
|
||||
Or you want to run two different instances of mysql, 5.2 and
|
||||
5.5. Same thing applies plus you have to also make sure the two
|
||||
mysqlclient libraries do not collide.
|
||||
</para>
|
||||
<para>
|
||||
This is not impossible but very inconvenient. If you want to
|
||||
install two whole stack of software like GNOME 3.10 and GNOME
|
||||
3.12, you can imagine the amount of work.
|
||||
</para>
|
||||
<para>
|
||||
From an administrator view point: containers to the rescue. The
|
||||
solution nowadays is to create a container per service,
|
||||
especially when different versions are needed. That somehow
|
||||
solves the problem, but at a different level and with other
|
||||
drawbacks. Needing orchestration tools, setting up a shared
|
||||
cache of packages, and new wild machines to monitor rather than
|
||||
simple services.
|
||||
</para>
|
||||
<para>
|
||||
From a developer view point: virtualenv for python or jhbuild
|
||||
for gnome or whatelse. But then, how do you mix the two stacks?
|
||||
How do you avoid recompiling the same thing when it could be
|
||||
instead be shared? Also you need to setup your development
|
||||
tools to point to the different directories where libraries are
|
||||
installed. Not only, there's the risk that some of the software
|
||||
incorrectly uses system libraries.
|
||||
</para>
|
||||
<para>
|
||||
And so on. Nix solves all this at the packaging level and
|
||||
solves it well. A single tool to rule them all.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title> Being pure functional</title>
|
||||
|
||||
<para>
|
||||
Nix does no assumption about the global state of the system.
|
||||
This has many advantages, but also some drawbacks of course.
|
||||
The core of a Nix based system is the Nix store, usually
|
||||
installed under /nix/store, and some tools to manipulate the
|
||||
store. In Nix there's the notion of derivation rather than
|
||||
package. The difference might be subtle at the beginning, so I
|
||||
will often mix both of the words, ignore that.
|
||||
</para>
|
||||
<para>
|
||||
Derivations/packages are stored in the nix store as follows:
|
||||
<literal>/nix/store/<replaceable>hash-name</replaceable></literal>,
|
||||
where the hash uniquely identifies the derivation (not true,
|
||||
it's a little more complex than this), and name is the name of
|
||||
the derivation.
|
||||
</para>
|
||||
<para>
|
||||
Let's take the bash derivation as example:
|
||||
<literal>/nix/store/s4zia7hhqkin1di0f187b79sa2srhv6k-bash-4.2-p45/</literal>.
|
||||
It is a directory that contains <literal>bin/bash</literal>.
|
||||
</para>
|
||||
<para>
|
||||
You get it, there's no <literal>/bin/bash</literal>, there's only that
|
||||
self-contained build output in the store. Same goes for
|
||||
coreutils and everything else. To make their usage convenient
|
||||
from the shell, nix will put those paths in
|
||||
<varname>PATH</varname>.
|
||||
</para>
|
||||
<para>
|
||||
What we have is basically a store of all packages and different
|
||||
versions of them, and things in the nix store are immutable.
|
||||
</para>
|
||||
<para>
|
||||
There's no ldconfig cache either. So where does bash find libc?
|
||||
</para>
|
||||
<screen><xi:include href="./01/which-bash.txt" parse="text" /></screen>
|
||||
<para>
|
||||
Turns out that when bash was built, it used that specific
|
||||
version of glibc and at runtime it will require exactly that
|
||||
glibc version.
|
||||
</para>
|
||||
<para>
|
||||
Don't be doubtful about the version in the derivation name:
|
||||
it's only a name for us humans. You may end up having a
|
||||
different hash given the same derivation name.
|
||||
</para>
|
||||
<para>
|
||||
What does it all mean? You could run mysql 5.2 with glibc-2.18,
|
||||
and mysql 5.5 with glibc-2.19. You could use your python module
|
||||
with python 2.7 compiled with gcc 4.6 and the same python
|
||||
module with python 3 compiled with gcc 4.8, all in the same
|
||||
system.
|
||||
</para>
|
||||
<para>
|
||||
In other words, no dependency hell, not even a dependency
|
||||
resolution algorithm. Straight dependencies from derivations to
|
||||
other derivations.
|
||||
</para>
|
||||
<para>
|
||||
From an administrator view point: need an old PHP version from
|
||||
lenny and want to upgrade to wheezy, not painful.
|
||||
</para>
|
||||
<para>
|
||||
From a developer view point: want to develop webkit with llvm
|
||||
3.4 and 3.3, not painful.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Mutable vs immutable</title>
|
||||
|
||||
<para>
|
||||
When upgrading a library, package managers replace it in-place.
|
||||
All new applications run afterwards with the new library
|
||||
without being recompiled. After all, they all refer dynamically
|
||||
to libc6.so.
|
||||
</para>
|
||||
<para>
|
||||
While being immutable with Nix, upgrading a library like glibc
|
||||
means recompiling all applications, because the glibc path to
|
||||
the nix store is being hardcoded.
|
||||
</para>
|
||||
<para>
|
||||
So how do we deal with security updates? In Nix we have some
|
||||
tricks (yet pure) to solve this problem, but that's another
|
||||
story.
|
||||
</para>
|
||||
<para>
|
||||
Another problem is that unless software has in mind a pure
|
||||
functional model, or it can be adapted to, it's hard to compose
|
||||
applications at runtime.
|
||||
</para>
|
||||
<para>
|
||||
Let's take for example firefox. You install flash, and you get
|
||||
it working because firefox looks in a global path for plugins.
|
||||
</para>
|
||||
<para>
|
||||
In Nix, there's no such global path for plugins. Firefox
|
||||
therefore must know explicitly about the path to flash. We wrap
|
||||
the firefox binary to setup the necessary environment to make
|
||||
it find flash in the nix store. That will produce a new firefox
|
||||
derivation: be aware it takes a few seconds, but it made
|
||||
composition harder at runtime.
|
||||
</para>
|
||||
<para>
|
||||
No upgrade/downgrade scripts for your data. It doesn't make
|
||||
sense with this approach, because there's no real derivation to
|
||||
be upgraded. With nix you switch to using another software with
|
||||
its own stack of dependencies, but there's no formal notion of
|
||||
upgrade or downgrade when doing so.
|
||||
</para>
|
||||
<para>
|
||||
Migrating to the new data format is your own responsibility.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Conclusion</title>
|
||||
<para>
|
||||
Nix lets you compose software at build time with maximum
|
||||
flexibility and with builds being as reproducible as possible.
|
||||
Not only, due to its nature deploying systems in the cloud is
|
||||
so easy, consistent and reliable that in the Nix world all
|
||||
existing self-containment and orchestration tools are
|
||||
deprecated by <link
|
||||
xlink:href="http://nixos.org/nixops/">NixOps</link>. Talking
|
||||
about this, no comparison with other tools is fair, Nix rocks.
|
||||
</para>
|
||||
<para>
|
||||
It however <emphasis>currently</emphasis> falls off when
|
||||
speaking about dynamic composition at runtime or replacing low
|
||||
level libraries due to massive rebuilds.
|
||||
</para>
|
||||
<para>
|
||||
That may sound scary, however after running NixOS on both a
|
||||
server and a laptop desktop, I'm very satisfied so far. Some of
|
||||
the architectural problems just need some man power, other
|
||||
design problems are to be solved as a community yet.
|
||||
</para>
|
||||
<para>
|
||||
Considering <link
|
||||
xlink:href="https://nixos.org/nixpkgs/">Nixpkgs</link> (<link
|
||||
xlink:href="https://github.com/NixOS/nixpkgs">github
|
||||
link</link>) is a completely new repository of all the existing
|
||||
software, with a completely fresh concept, and with few core
|
||||
developers but overall year-over-year increasing contributions,
|
||||
the current state is way more than acceptable and beyond the
|
||||
experimental stage. In other words, it's worth your investment.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Next pill...</title>
|
||||
|
||||
<para>
|
||||
...we will install Nix on top of your current system (I assume
|
||||
GNU/Linux, but we also have OSX users) and start inspecting the
|
||||
installed stuff.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
2
pills/01/which-bash.txt
Normal file
2
pills/01/which-bash.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
$ ldd `which bash`
|
||||
libc.so.6 => /nix/store/94n64qy99ja0vgbkf675nyk39g9b978n-glibc-2.19/lib/libc.so.6 (0x00007f0248cce000)
|
Loading…
Reference in a new issue