null

Nix: как я заменил кучу менеджеров версий пакетов одним

nvm use 18.10
pyenv local 3.12.5
goenv local 1.12.0
update-java-alternatives -s java-1.7.0-openjdk-amd64

Если вы почувствовали мою боль, то эта статья может оказаться полезной.

 

Менеджеры версий пакетов

Во время разработки программного обеспечения часто приходится сталкиваться с необходимостью использования разных версий языков программирования и их пакетов в зависимости от проекта. Например, справедливо предположить, что в более новом проекте на Node.js будет использована более новая версия ноды. Однако, старый проект тоже необходимо поддерживать, а значит возникает необходимость в хранении нескольких версий Node.js и обеспечении возможности переключения между ними (если вы, конечно, не решите обновить ноду в более старом проекте, что не всегда хорошая затея).

Для этой цели существуют такие инструменты, как nvm (для Node.js), pyenv (для Python), goenv (для Go) и многие другие. Однако, наличие кучи менеджеров версий пакетов утомляет: каждый из них имеет свои особенности, команды и конфигурации. В этой статье мы рассмотрим, как инструмент nix-shell из пакетного менеджера Nix может стать универсальной альтернативой.

 

Что такое Nix и nix-shell?

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

В некотором смысле, Nix - полноценная замена apt, pacman и прочим пакетным менеджерам с тем отличием, что Nix позволяет иметь несколько версий одной и той же зависимости. Важной характеристикой является декларативное управление зависимостями с помощью конфигурационного файла (в этом плане он чем-то напоминает package.json в проектах на ноде), в отличие от тех же apt и pacman с их императивным подходом.

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

Nix и nix-shell предлагают единый подход к управлению версиями и зависимостями для всех языков.

 

Установка Nix

curl -L https://nixos.org/nix/install | sh

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

 

Как использовать nix-shell

Рассмотрим на примере nvm, как его можно заменить с помощью nix-shell. Для этого нам понадобится файл конфигурации shell.nix, который описывает зависимости окружения.

Вместо использования nvm для переключения между версиями Node.js, вы можете указать нужную версию в shell.nix. Например:

{ pkgs ? import <nixpkgs> {} }: 
pkgs.mkShell { 
  buildInputs = [ 
    pkgs.nodejs-18_x # Указываем конкретную версию Node.js 
    pkgs.yarn # Опционально: добавляем Yarn 
  ]; 
}

Сохраните этот код в файл shell.nix в корне проекта. Затем выполните:

nix-shell

Вы окажетесь в окружении с Node.js версии 18.x и Yarn, доступными в командной строке. Чтобы использовать другую версию, просто измените nodejs-18_x на, например, nodejs-20_x.

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

 

Но... Чем это отличается от Docker?

Почему бы просто не положить в репозиторий уже всем привычный Dockerfile, вместо ранее упомянутого shell.nix?

И Docker, и Nix выполняют похожие задачи: изолируют приложение с его зависимостями от остальной системы и обеспечивают воспроизводимость этой комбинации. Однако, оба имеют свои плюсы и минусы, и, как мне кажется, Nix лучше отвечает интересам разработки.

Во-первых, nix-shell работает на уровне пользовательского пространства и не требует запуска контейнеров. Docker требует демона, образа контейнера и изоляции на уровне ядра, что добавляет накладные расходы, особенно для небольших задач.

Во-вторых, в nix-shell вы работаете в окружении, которое "накладывается" на вашу хост-систему. Это значит, что ваши файлы, редакторы, настройки и инструменты остаются доступными без необходимости монтирования томов или настройки контейнера. В Docker вам нужно явно монтировать директории, передавать переменные окружения и настраивать доступ к хост-системе, что усложняет быстрый старт.

В-третьих, Nix хранит все пакеты в глобальном хранилище (/nix/store) и переиспользует их между проектами. Если вы уже скачали Node.js 18.x для одного проекта, он будет мгновенно доступен для другого без повторной загрузки. Docker тоже кэширует слои, но образы создаются для каждого проекта отдельно, что может привести к дублированию данных на диске.

 

Заключение

nix-shell — это мощный инструмент, который может заменить множество менеджеров версий, таких как nvm, pyenv, goenv. Он гарантирует одинаковую среду на всех машинах, позволяет зависимости для нескольких языков в одном окружении и обеспечивает изоляцию окружений.

Вперед