Предисловие


В 2014 и 2015 годах Люка Бруно (Luca Bruno aka Lethalman) опубликовал серию постов, описывающих пакетный менеджер Nix, операционную систему NixOS и хранилище Nixpkgs.


Люка назвал свои посты пилюлями (англ. pill — таблетка, пилюля).


Берясь за перевод, я пытался выяснить, нет ли у выражения in pills устойчивого смысла.
Оказалось, что скрытый смысл есть у самого слова Nix.
Это одна из торговых марок перметрина — средства против клещей, которое доступно только в виде мази.
Иными словами, медицинского Никса ни в пилюлях, ни в таблетках не бывает.


С момента публикации, Nix в пилюлях считается классическим введением в Nix. В 2017 году Грэм Кристиансен (Graham Christensen aka grahamc/gchristensen) инициировал работу по переводу серии статей в формат электронной книги.


Актуальную оригинальную версию книги вы найдёте по адресу https://nixos.org/guides/nix-pills/.
Там же доступен вариант в формате EPUB.


В 2024 году Марк Шевченко начал перевод книги на русский язык.
Актуальная версия доступна по адресу https://nix-pills-ru.github.io.


?

В примерах, команды, которые начинаются с символа "решётка" (#), должны быть запущены с правами пользователя root.

(Адрес статьи на официальном сайте перевода).


Почему вам стоит попробовать Nix


Введение


Добро пожаловать в первую статью из серии "Nix в пилюлях".
Nix — это чистый функциональный пакетный менеджер и система развёртывания для POSIX-совместимых ОС.


Есть немало материалов, посвящённых Nix, NixOS и связанным проектам.
И вы, возможно, даже не стали бы их читать, так что цель этой статьи --- убедить вас попробовать Nix.
Установка NixOS не потребуется, впрочем, иногда я буду ссылаться на NixOS, как на реальный пример операционной системы, построенной на базе Nix.


Почему появилась эта серия?


Руководства по Nix, Nixpkgs и NixOS вместе с вики --- великолепные ресурсы, объясняющие, как устроены Nix/NixOS, как их использовать, и насколько крутые штуки они позволяют делать.


Цель этих статей --- дополнить существующие документы чуть менее формальными объяснениями.


Теперь мы познакомимся с Nix.
Пилюли бывают горькими, поэтому постараюсь закончить всё как можно быстрее.


Когда пакетный менеджер — не чистый функциональный


Большинство, если не все, популярных пакетных менеджеров (dpkg, rpm, ...) изменяют глобальное состояние системы.
Установив пакет foo-1.0 в каталог /usr/bin/foo, вы не сможете установить туда же foo-1.1, пока не измените путь установки или имя исполняемого файла.
Впрочем, изменение имени файла обманывает ожидания пользователей пакета.


Есть разные способы снять эту проблему. Например, Debian, частично решает её с помощью системы альтернатив.


Так что в теории мы можем установить несколько версий одного пакета, но на практике такой опыт может быть болезненным.


Скажем, вам нужен сервис nginx и, кроме него --- сервис nginx-openresty.
Вы должны создать новый пакет, и поменять в нём все пути, например, добавив к ним суффикс -openresty.


Или — представим — вам надо запустить разные версии mysql: 5.2 и 5.5.
Возникнет та же свистопляска с путями, что и раньше.
Кроме того, вам надо будет убедиться, что разные версии библиотеки mysqlclient не конфликтуют друг с другом.


Такая ситуация может возникнуть, и, если она возникнет, справиться с ней будет очень непросто.
А если вы захотите установить два различных программных стека, скажем, GNOME 3.10 и GNOME 3.13, вам можно только посочувствовать.


Администраторы скажут: вы можете использовать контейнеры.
Типичный подход в наши дни — создать контейнер для каждого сервиса, особенно, если речь идёт о разных версиях.
Подход в какой-то степени решает проблему, но на другом уровне и с другими побочными эффектами.
Скажем, вам потребуется средства оркестрации, настройка разделяемого кэша пакетов и новые машины для мониторинга всего этого счастья — вместо пары простых сервисов.


Разработчики скажут: вы можете использовать virtualenv для python, или jhbuild для gnome, или что-то ещё для чего-то ещё.
Но как вы смешаете разные стеки?
Как вам избежать перекомпиляции исходников, если их надо разделить между проектами?
А ещё вам придётся настроить инструменты разработки, чтобы они загружали библиотеки из правильных каталогов.
И, наконец, всегда остаётся риск, что часть софта некорректно работает с системными библиотеками.


И так далее.
Nix решает все эти проблемы на уровне пакетов и решает их хорошо.
Один инструмент --- чтобы управлять всеми пакетами.


Когда пакетный менеджер — чистый функциональный


Nix не делает никаких предположений о глобальном состоянии системы.
У этого подхода есть много преимуществ, но, конечно, есть и недостатки.
Сердцем системы Nix является хранилище, обычно расположенное в /nix/store, а также кое-какие инструменты для работы с ним.
В Nix вместо понятия пакет существует понятие порождение или деривация (derivation).
Для новичков различия между ними кажутся слишком тонкими, поэтому я буду использовать эти слова, как синонимы.


Порождения/пакеты хранятся в хранилище Nix в соответствии с форматом /nix/store/hash-name, где хэш (hash) однозначно идентифицирует порождение (это не совсем правда, на самом деле всё чуть сложнее), а имя (name) — это имя порождения.


Взглянем, для примера, на порождение bash: /nix/store/s4zia7hhqkin1di0f187b79sa2srhv6k-bash-4.2-p45/.
Это каталог в хранилище Nix, где находится утилита bin/bash.


Фактически это означает, что в системе нет никакой глобальной оболочки, а есть только эта конкретная версия в одном из каталогов хранилища.
То же касается и других утилит, да и вообще всего.
Чтобы утилиты можно было вызывать из командной строки, Nix следит за тем, чтобы в переменной PATH были правильные пути.


В итоге у нас есть хранилище всех пакетов (разные версии пакетов хранятся в разных каталогах), и всё, что там есть --- менять нельзя.


Фактически, в системе нет даже кэша ldconfig.
Как, в таком случае, bash находит libc?


$ ldd  `which bash`
libc.so.6 => /nix/store/94n64qy99ja0vgbkf675nyk39g9b978n-glibc-2.19/lib/libc.so.6 (0x00007f0248cce000)

Дело в том, что когда bash был собран, он был собран с конкретной версией glibc из хранилища Nix, и при запуске он загружает именно эту версию glibc.


Пусть вас не смущает номер версии в имени порождения: это имя для нас, людей.
Мы можете создать два порождения с одним и тем же именем, но разными хэшами: значение имеет только хэш.


Для чего все эти сложности?
Благодаря им, вы теперь можете запускать mysql 5.2 с glibc-2.18 и mysql 5.5 с glibc-2.19.
Вы можете использовать ваш модуль c python 2.7, собранным gcc 4.6 и тот же самый модуль — с python 3, собранным gcc 4.8, в одной и той же системе.


Другими словами: никакого больше ада зависимостей (dependency hell) и даже никакого алгоритма разрешения зависимостей.
Прямые зависимости порождений от других порождений.


Администраторы скажут: если вам нужна старая версия PHP для одного приложения, но вы хотите обновить всю остальную систему, это можно сделать безболезненно.


Разработчики скажут: если вы хотите разрабатывать webkit и llvm 3.4 и с llvm 3.3, это можно сделать безболезненно.


Изменяемое против неизменного


При обновлении библиотеки большинство пакетных менеджеров просто перезаписывают файл в каталоге.
Потом все приложения запускаются с новой версией без перекомпиляции.
Ненадёжно, но кого это волнует? В конце концов, все приложения динамически ссылаются на libc6.so.


Поскольку порождения Nix неизменны (иммутабельны), обновление библиотеки наподобие glibc требует перекомпиляции всех приложений, потому что путь к glibc в хранилище Nix зависит от версии.


Как же нам быть с обновлениями безопасности?
У нас в Nix есть несколько трюков (всё ещё чистых), чтобы справиться с этой проблемой, но это другая история.


Другая проблема заключается в том, что если софт не разрабатывался с расчётом на запуск из каталога только для чтения, или его нельзя адаптировать к такому запуску, его может быть трудно заставить работать.


Возьмём для примера Firefox.
В большинстве системы вы устанавливаете flash, и он просто начинает работать, потому что Firefox ищет плагины по глобальному пути.


В Nix не существует никого глобального пути для плагинов.
Firefox должен точно знать, где находится flash.
Мы справляемся с этой проблемой, создавая для Firefox особое окружение, позволяющее найти flash в хранилище Nix.
В результате будет создано новое порождение Firefox: это займёт несколько секунд, и сделает настройку чуть более сложной.


Вам больше не нужны скрипты обновления/удаления ваших данных.
В этом просто нет смысла, потому что не бывает порождений, которые можно было бы обновлять.
В Nix вы переключаетесь на другой софт со своим собственным набором зависимостей, но при этом нет никаких обновлений или удалений.


Если изменился формат данных, то миграция на новый формат --- это ваша ответственность.


Заключение


Nix позволяет с максимальной гибкостью управлять сборкой программ, оставляя их настолько воспроизводимыми (идентичными), насколько это вообще возможно.
Более того, из-за природы Nix, разворачивание в облаке настолько простое, что в мире Nix все инструменты контейнеризации и оркестрации безнадёжно устарели по сравнению с NixOps.


Тем не менее, Nix пока не справляется с динамической компоновкой при работе программ, или с заменой низкоуровневых библиотек, из-за того, что всё это требует перекомпиляции.


Это может звучать пугающе, однако после запуска NixOS и на сервере, и на десктопе, я очень доволен.
Конечно, некоторые архитектурные проблемы нуждаются в человеческих ресурсах, в то время, как другие по-прежнему требуют решения со стороны сообщества разработчиков.


Взглянув на Nixpkgs (ссылка на github) — совершенно новый репозиторий всего существующего софта, с совершенно свежим подходом, с небольшим количеством основных разработчиков, но с растущим год от года вкладом сообщества, мы должны признать, что он вышел из стадии эксперимента, и его состояние более чем удовлетворительно.
Иными словами, он стоит потраченного на него времени.


В следующей пилюле


… мы установим Nix в вашу систему (предположительно GNU/Linux, но подойдёт и OSX), и начнём его изучать.

Комментарии (8)


  1. mayorovp
    02.04.2024 06:33
    +2

    Насчёт "никакого больше ада зависимостей" вы несколько погорячились: да, администраторам стало проще, но разработчикам всё ещё нужно искать и согласовывать эти самые зависимости.

    Но я вижу другую проблему. А что делать с плагинами? К примеру, как программы, использующие систему PAM, смогут загружать модули, если каждый модуль скомпилирован со своей версией стандартной библиотеки?


  1. garwall
    02.04.2024 06:33
    +2

    Сам Nix не использовал, но пришлось работать со Spack, и в целом впечатления средненькие. "ад зависимостей" превращается в "ад энвайроментов" и начинает жрать дисковое пространство с изрядной скоростью.

    Ну т.е. в целом, если подразумевается заморозка зависимостей и отсутствие человеческого участия, то работать будет хорошо, но в противном случае количество вылезающих нюансов может просто убить весь эффект функциональности и декларативности


  1. ri1wing
    02.04.2024 06:33
    +1

    Я запутался.

    Так обновление библиотеки требует перекомпиляции всех пакетов, которые на неё ссылаются или в Nix

    не бывает порождений, которые можно было бы обновлять. В Nix вы переключаетесь на другой софт со своим собственным набором зависимостей, но при этом нет никаких обновлений или удалений.

    ?


  1. 13werwolf13
    02.04.2024 06:33
    +2

    интересно почему NIXos до сих пор не задействует для своих "особенностей" сабволюмы btrfs/zfs/bcachefs..

    алсо, моё скромное мнение не претендует на 100% верность, но кмк nix отличная штука как задумка, но весьма странная штука в реализации.


  1. UncleSam27
    02.04.2024 06:33

    А потом ты понимаешь, что для того чтобы полноценно пользоваться этой системой сборки тебе надо выучить отдельный язык программирования, довольно специфический и по сути не применяемый больше ни где вообще. И руки тянутся к Buildroot.


  1. easimonenko
    02.04.2024 06:33
    +4

    Не так давно стал пользоваться Nix поверх Ubuntu. Понравилось. В этом сочетании Ubuntu только базовая, та, что при установке ставится. Всё остальное подтягиваю через Nix. Работает это по мне лучше чем Apt плюс Snap. В Nix есть почти всё, что мне нужно. В канале unstable свежие версии пакетов. Раньше приходилось многое собирать из исходников. А пакеты из Snap попадались криво работающие. Да и работает Snap как-то капризно и непрозрачно. На саму NixOS ещё не перешёл, не дошли руки как следует поэкспериментировать.

    Ещё смотрел концептуально похожий Guix. Пока не сложилось. Ставил и как дополнительный менеджер пакетов, и как самостоятельную систему. Как менеджер работает медленно, не всегда успешно. Возможно сервер пакетов Guix медленный. Спектр пакетов примерно такой же как у Nix. Установить Guix как полную систему успешно не получилось, к тому же ядро в ней Libre. Преднастроенного рабочего стола нет. Зато всё написано на Scheme. В общем больше для ценителей пока.


  1. phikus
    02.04.2024 06:33
    +1

    Традиционно каждый год здесь выходят статьи про Nix. В прошлый раз я, поддавшись ажитации, попробовал поставить NixOS, но инсталлятор даже не смог видеокарту определить. Так закончилось моё знакомство с этой системой ¯\_(ツ)_/¯


  1. m_ax1m
    02.04.2024 06:33

    Обожаю Nix. Это просто лучшая технология. Из минусов только место на диске, и концепция double config, ну может вначале тяжеловато изучать. Но дайте шанс никсу, перетерпите чутка начальные этапы. Надеюсь как можно больше людей втянется, и эта штука распространится. Это же круто, когда конфигурируешь абсолютно все в декларативном стиле, и накатываешь одной командой в прод. Есть библиотеки для билдов на любом языке программирования , Hercules ci / arion для девопса и контейнеров. Все в универсальном формате. Вообще с никсом даже на баше одно удовольствие писать.