6 Basic work with nix
Izorkin edited this page 1 year ago

В предыдущей статье Базовая установка и настройка NixOS мы ознакомились с ОС NixOS. Теперь посмотрим возможности пакетного менеджера nix.

Nix - чисто функциональный менеджер пакетов. Он рассматривает пакет как значения в чисто функциональных языках программирования - они создаются функциями, не имеющих побочных эффектов, и никогда не меняются после сборки. Пакетный менеджер хранит все пакеты в своём хранилище, расположенном в каталоге /nix/store. Каждый пакет имеет свой собственный уникальный подкаталог в формате ${hash}-${name}-${version}, где:

  • hash - уникальный идентификатор, который рассчитывается на основе криптографического хэша графа зависимостей сборки пакета.
  • name - имя пакета.
  • version - версия пакета.

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

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

При сборке пакета менеджер nix создаёт уникальное окружение, в которое включаются только указанные зависимости, и такие инструменты, как компиляторы, производят поиск зависимостей только в этом окружении. Также nix не устанавливает пакеты в глобальных местах, например в /usr/bin, что значительно снижает риск неполных зависимостей.

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

Операции управления пакетами никогда не перезаписывают пакеты в хранилище nix, пакеты просто добавляются по разным путям. Во время обновления пакета нет временного окна, в котором есть некоторые файлы из старой версии и некоторые файлы из новой версии. При удалении пакета он не сразу удаляется из системы. Такие операции называются атомарными обновлениям и откатами. Такой подход позволяет вернуться к старой версии пакета либо сменить профиль из набора пакетов. Для полного удаления неиспользуемых пакетов необходимо запустить сборщик мусора. Он удаляет все пакеты, которые не используются ни одним из профилем пользователя либо системы.

Источником обновления пакетов для менеджера nix служат каналы. По умолчанию в системе прописан стабильный канал:

sudo nix-channel --list
nixos https://channels.nixos.org/nixos-20.03

Так как мы используем нестабильную ветку, канал обновления будет таким:

sudo nix-channel --list
nixos https://nixos.org/channels/nixos-unstable

Список всех каналов обновления можно посмотреть на странице https://channels.nixos.org/. Для каждого отдельного пользователя можно прописать отдельные каналы. Сейчас у пользователя rebrain каналы не прописаны и команда nix-channel --list выдаст пустую строку. Добавим канал с последними обновлениями пакетов и обновим его:

nix-channel --add https://channels.nixos.org/nixos-unstable-small nixpkgs
nix-channel --update

Использование каналов позволяет:

  • зафиксировать ПО на определённой версии.
  • использовать устаревшее ПО, например, если какие-либо скрипты не поддреживают новую версию и требуют доработки.

Поиск пакетов производится командой nix search <FLAGS>... <REGEX>..., флаг -u обновляет кэш программ. Например:

nix search htop

выдаст:

warning: using cached results; pass '-u' to update the cache
* nixpkgs.bpytop (bpytop-1.0.0)
  A resource monitor; python port of bashtop

* nixpkgs.htop (htop)
  An interactive process viewer for Linux

* nixpkgs.zenith (zenith-0.10.0)
  Sort of like top or htop but with zoom-able charts, network, and disk usage

где nixpkgs имя нашего канала, bpytop - имя пакета.

Установить пакет можно несколькими способами:

  • прописать название пакета в /etc/nixos/configuration.nix, в нашем случае в /etc/nixos/nix-config/generic/pkgs.nix в блок environment.systemPackages и перезапустить сборку системы;
  • выполнить команду nix-env -i bpytop, но в этом случае, из-за специфики работы, пакетный менеджер начнёт анализировать содержимое канала и потреблять много оперативной памяти;

При установке с помощью nix-env рекомендуется указать флаг -A, канал обновления и полное имя пакета:

nix-env -iA nixpkgs.bpytop
installing 'bpytop-1.0.0'
these paths will be fetched (0.33 MiB download, 1.63 MiB unpacked):
  /nix/store/k9spzc7yhj99a0pi19ryxmr4a2kz1zf5-python3.8-psutil-5.7.0
  /nix/store/xgd78r2k3n38pqagnrrkh1mn8fwdlkr9-bpytop-1.0.0
copying path '/nix/store/k9spzc7yhj99a0pi19ryxmr4a2kz1zf5-python3.8-psutil-5.7.0' from 'https://cache.nixos.org'...
copying path '/nix/store/xgd78r2k3n38pqagnrrkh1mn8fwdlkr9-bpytop-1.0.0' from 'https://cache.nixos.org'...
building '/nix/store/pffd5xbrbz7xrg07in0gz8jy4vgqlzd7-user-environment.drv'...
created 3 symlinks in user environment
Time: 0h:00m:03s

После установки пакет bpytop не будет виден в текущем сеансе (не сработает автодополнение команды). Надо либо перезайти в систему, либо обновить переменную $PATH следующей командой:

rehash
bpytop --version
bpytop version: 1.0.0
psutil version: 5.7.0

Список установленных пакетов можно посмотреть командой:

nix-env -q | cat
bpytop-1.0.0

Так же как и в системе поддерживаются точки отката (список генераций), можно посмотреть командой:

nix-env --list-generations | cat
   1   2020-08-09 12:08:56   (current)

Поставим ещё один пакет:

nix-env -iA nixpkgs.mariadb-client
installing 'mariadb-client-10.4.13'
these paths will be fetched (1.84 MiB download, 40.25 MiB unpacked):
  /nix/store/48xcq4hxg78y1shn1wfg3z4xvcmim865-mariadb-client-10.4.13-man
  /nix/store/9i890ymiw4njc26d6ccjwlgkw2v4g6vs-mariadb-client-10.4.13
copying path '/nix/store/48xcq4hxg78y1shn1wfg3z4xvcmim865-mariadb-client-10.4.13-man' from 'https://cache.nixos.org'...
copying path '/nix/store/9i890ymiw4njc26d6ccjwlgkw2v4g6vs-mariadb-client-10.4.13' from 'https://cache.nixos.org'...
building '/nix/store/r03ghp0kr48nsab4mavnq4hczfrsih8i-user-environment.drv'...
warning: skipping dangling symlink '/nix/store/f1lgp5c7qypy6ggf3wa36p65i9451iqs-user-environment/bin/mariadb-test'
created 33 symlinks in user environment
Time: 0h:00m:03s

И посмотрим список генераций:

nix-env --list-generations | cat
   1   2020-08-09 12:08:56
   2   2020-08-09 12:11:30   (current)

Теперь у нас 2 списка. Переключаться между ними можно командой:

nix-env --switch-generation 1
switching from generation 2 to 1
mysql --version
mysql: command not found

Примечание: в последних обновлениях базовой конфигурации NixOS в git репозитории пакет mariadb-client уже установлен. В итоге команда mysql --version всё равно сработает. Поэтому, для примера, пакет можно заменить на go - nix-env -iA nixpkgs.go_1_16 и go version.

nix-env --switch-generation 2
switching from generation 1 to 2
mysql --version
mysql  Ver 15.1 Distrib 10.4.13-MariaDB, for Linux (x86_64) using readline 5.1

Установленные пакеты можно удалить командой:

nix-env -e bpytop mariadb-client

Очистить список генераций можно командой:

nix-env --delete-generations 1 2

Так же пакетный менеджер nix поддерживает профили установленных пакетов и возможность переключения между ними:

nix-env --switch-profile /nix/var/nix/profiles/per-user/rebrain/profile-test

Команда nix-env -q | cat выдаст пустой результат.

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

Например нам требуется две версии nodejs 12_x и nodejs 8_x, которая сейчас уже не поддерживается в текущей версии. Версию nodejs 8_x можно найти на канале nixos-19.03. Добавляем канал:

nix-channel --add https://channels.nixos.org/nixos-19.03 nixpkgs-1903
nix-channel --update

Создаём новый профиль:

nix-env --switch-profile /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-8x

И устанавливаем nodejs 8_x:

nix-env -iA nixpkgs-1903.nodejs-8_x
installing 'nodejs-8.15.1'
these paths will be fetched (29.48 MiB download, 141.05 MiB unpacked):
  /nix/store/0d12kpv6fp3w2p9bjskbrhyx1vjz7384-http-parser-2.9.0
  /nix/store/0f1bal83favkgrr5mp5crw9mqrzi85b7-zlib-1.2.11
  /nix/store/4g3g1l0vii6nj6jiq70gpbikb7vclmcj-bzip2-1.0.6.0.1
  /nix/store/5my64vz61d64dppj1bdhax4mnc8x6rpa-nodejs-8.15.1
  /nix/store/5s4v1ska7pgdfj4brzkcab9kq56a0jzc-acl-2.2.53
  /nix/store/94faqmx1gwc88lrgj5dnfm9xxaf54cc0-openssl-1.0.2u
  /nix/store/9sp131l64cxncjxr2znk5v797vbl57ch-gdbm-1.18.1
  /nix/store/a13810j3gfm6nss503qwnqc2pgsawmlw-db-5.3.28
  /nix/store/czqwvknixch95pw1kcvrj5zzwk7r4py6-python-2.7.17
  /nix/store/f09zmq3sqiy0dnx8g4f1arngkjd4kih7-gcc-7.4.0-lib
  /nix/store/h0p0h3rh1q4i2yavzm3yqi716s9yaj2f-glibc-2.27
  /nix/store/issgq20n7k0z2dvgdsdgijrbd7j5fqvn-ncurses-6.1-20190112
  /nix/store/jargvpajyq21wxjaib1fj4lbnapmd7d2-libuv-1.26.0
  /nix/store/jyxphfkij1il4ip6y34832v9gakg3pqy-attr-2.4.48
  /nix/store/kzv56yx369j0jvcza2cphj2pv8xmqga4-bash-4.4-p23
  /nix/store/pqx8wsc4kx87f587b81aj4fgjshgjvi8-readline-6.3p08
  /nix/store/q2s80z6hhw1gi3wa14v5a1zppkqk9c2p-coreutils-8.30
  /nix/store/ya74davhsdfa5y0dycj75am4pps5cdq9-sqlite-3.28.0
copying path '/nix/store/h0p0h3rh1q4i2yavzm3yqi716s9yaj2f-glibc-2.27' from 'https://cache.nixos.org'...
copying path '/nix/store/jyxphfkij1il4ip6y34832v9gakg3pqy-attr-2.4.48' from 'https://cache.nixos.org'...
copying path '/nix/store/kzv56yx369j0jvcza2cphj2pv8xmqga4-bash-4.4-p23' from 'https://cache.nixos.org'...
copying path '/nix/store/4g3g1l0vii6nj6jiq70gpbikb7vclmcj-bzip2-1.0.6.0.1' from 'https://cache.nixos.org'...
copying path '/nix/store/5s4v1ska7pgdfj4brzkcab9kq56a0jzc-acl-2.2.53' from 'https://cache.nixos.org'...
copying path '/nix/store/f09zmq3sqiy0dnx8g4f1arngkjd4kih7-gcc-7.4.0-lib' from 'https://cache.nixos.org'...
copying path '/nix/store/9sp131l64cxncjxr2znk5v797vbl57ch-gdbm-1.18.1' from 'https://cache.nixos.org'...
copying path '/nix/store/q2s80z6hhw1gi3wa14v5a1zppkqk9c2p-coreutils-8.30' from 'https://cache.nixos.org'...
copying path '/nix/store/0d12kpv6fp3w2p9bjskbrhyx1vjz7384-http-parser-2.9.0' from 'https://cache.nixos.org'...
copying path '/nix/store/a13810j3gfm6nss503qwnqc2pgsawmlw-db-5.3.28' from 'https://cache.nixos.org'...
copying path '/nix/store/jargvpajyq21wxjaib1fj4lbnapmd7d2-libuv-1.26.0' from 'https://cache.nixos.org'...
copying path '/nix/store/issgq20n7k0z2dvgdsdgijrbd7j5fqvn-ncurses-6.1-20190112' from 'https://cache.nixos.org'...
copying path '/nix/store/94faqmx1gwc88lrgj5dnfm9xxaf54cc0-openssl-1.0.2u' from 'https://cache.nixos.org'...
copying path '/nix/store/0f1bal83favkgrr5mp5crw9mqrzi85b7-zlib-1.2.11' from 'https://cache.nixos.org'...
copying path '/nix/store/pqx8wsc4kx87f587b81aj4fgjshgjvi8-readline-6.3p08' from 'https://cache.nixos.org'...
copying path '/nix/store/ya74davhsdfa5y0dycj75am4pps5cdq9-sqlite-3.28.0' from 'https://cache.nixos.org'...
copying path '/nix/store/czqwvknixch95pw1kcvrj5zzwk7r4py6-python-2.7.17' from 'https://cache.nixos.org'...
copying path '/nix/store/5my64vz61d64dppj1bdhax4mnc8x6rpa-nodejs-8.15.1' from 'https://cache.nixos.org'...
building '/nix/store/gdzf45fk3x6zqvdpswndjlg2mlgirxmw-user-environment.drv'...
created 4 symlinks in user environment
Time: 0h:00m:12s

Проверяем версию:

node --version
v8.15.1

Примечание: при запуске пакета, собранного в других релизах ОС NixOS может возникнуть такая ошибка:

node: /nix/store/h0p0h3rh1q4i2yavzm3yqi716s9yaj2f-glibc-2.27/lib/libc.so.6: version `GLIBC_2.32' not found (required by /nix/store/dhrv3pfmhs88kszriqp70fmadvyfy6m6-malloc-provider-jemalloc/lib/libjemalloc.so)

Такое случается если испльзуется бибилиотека glib разных версии и менеджер память jammalloc. Можно удалить параметр memoryAllocator.provider в файле /etc/nixos/nix-config/core.nix и перезапустить сборку системы. Либо удалить файл /etc/ld-nix.so.preload

sudo rm /etc/ld-nix.so.preload

Ставим nodejs 12_x уже с последнего канала:

nix-env --switch-profile /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-12x
nix-env -iA nixpkgs.nodejs-12_x
installing 'nodejs-12.18.3'
these paths will be fetched (11.78 MiB download, 61.21 MiB unpacked):
  /nix/store/97fy125s2km6j82qm1449qf4sqr3qski-libuv-1.38.1
  /nix/store/bn3n6aa85xifhnidqq31679iszr3xvmr-nodejs-12.18.3
  /nix/store/rdvambcpxagx4z91fyy69zgm71ibz6bh-icu4c-67.1-dev
copying path '/nix/store/rdvambcpxagx4z91fyy69zgm71ibz6bh-icu4c-67.1-dev' from 'https://cache.nixos.org'...
copying path '/nix/store/97fy125s2km6j82qm1449qf4sqr3qski-libuv-1.38.1' from 'https://cache.nixos.org'...
copying path '/nix/store/bn3n6aa85xifhnidqq31679iszr3xvmr-nodejs-12.18.3' from 'https://cache.nixos.org'...
building '/nix/store/4ap8npfayfjwai58v6hdyrgpaqvb4fzz-user-environment.drv'...
created 4 symlinks in user environment
Time: 0h:00m:05s
node --version
v12.18.3

В зависимости от того какая версия nodejs требуется переключаемся между профилями profile-nodejs-8x и profile-nodejs-12x.

nix-env --switch-profile /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-8x
node --version
nix-env --switch-profile /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-12x
node --version

Все пользовательские профили находятся в папке /nix/var/nix/profiles/per-user. Ненужные профили можно удалить командой rm:

rm /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-8x*
rm /nix/var/nix/profiles/per-user/rebrain/profile-nodejs-12x*

После этого можно очистить систему от старых генераций, созданных пользователем rebrain:

nix-collect-garbage --delete-old

В последующем, чтобы обновить пакеты, сперва обновляем каналы:

nix-channel --update

Потом пакеты. Процесс запуска nix-env -u занимает продолжительное время:

nix-env -u

Также пакетный менеджер nix можно установить и на другой дистрибутив Linux командой:

curl -L https://nixos.org/nix/install | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  2490  100  2490    0     0   2011      0  0:00:01  0:00:01 --:--:--  3351
downloading Nix 2.3.7 binary tarball for x86_64-linux from 'https://releases.nixos.org/nix/nix-2.3.7/nix-2.3.7-x86_64-linux.tar.xz' to '/tmp/nix-binary-tarball-unpack.wglugpsGP1'...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 16.4M  100 16.4M    0     0  8536k      0  0:00:01  0:00:01 --:--:-- 8536k
Note: a multi-user installation is possible. See https://nixos.org/nix/manual/#sect-multi-user-installation
performing a single-user installation of Nix...
directory /nix does not exist; creating it by running 'mkdir -m 0755 /nix && chown rebrain /nix' using sudo
copying Nix to /nix/store......................................
installing 'nix-2.3.7'
building '/nix/store/b64sdzfcc4wd2p656i9jskxdmhjkq0cv-user-environment.drv'...
created 6 symlinks in user environment
unpacking channels...
created 1 symlinks in user environment
modifying /home/rebrain/.profile...
modifying /home/rebrain/.zshrc...

Installation finished!  To ensure that the necessary environment
variables are set, either log in again, or type

  . /home/rebrain/.nix-profile/etc/profile.d/nix.sh

in your shell.
Time: 0h:00m:16s

После перезахода в шелл:

nix --version
nix (Nix) 2.3.7
nix-channel --list
nixpkgs https://nixos.org/channels/nixpkgs-unstable

Принцип работы на других дистрибутивах с nix сохраняется прежним.