下个时代的开发工具-Nix:声明式的运行环境构建器、简单场景下的docker替身

发布于:2024-10-10 ⋅ 阅读:(7) ⋅ 点赞:(0)

个人的一点拙见 : 声明式范式会成为以后软件工程靠近应用侧主要的开发方式。比较典型的包括Docker,算是一个老前辈,晚一点在介绍。先来一个比较基础的,Nix

在开发的过程中,相信小伙伴们肯定用到一些环境管理的工具,用于维护某个工具的不同版本。当然也可以通过环境变量配置,但切换总是挺麻烦的。例如nvm管理不同的nodejs,miniconda管理不同的python版本,但切换过程中还是挺繁琐的,甚至遇到一些问题,在以前的文章nvm不可用报错`GLIBC_2.27‘‘GLIBCXX_3.4.20‘not Found?+ 使用docker构建多个前端项目实践就介绍了一种情况,以及推荐用docker来解决,但docker也存在一定问题-就是需要虚拟化环境支持,在某些场景下可能就不适用了。

1. 简介

Nix 是一个独特的包管理工具和构建系统,它采用了一种声明式的方法来管理软件包和运行环境。与传统的包管理器(如 aptyumbrew 等)不同,Nix 提供了一种以函数式编程理念为基础的机制,通过精确控制依赖关系和环境配置,确保软件的可重复性、隔离性和可追溯性。

什么是声明式运行环境?

声明式运行环境的核心思想是:用户描述“是什么”而不是“如何实现”。用户只需要定义软件环境的期望状态,Nix 会自动处理如何实现这一状态。这种方式与传统的命令式操作不同,后者要求用户逐步指定每个步骤。

2. Nix 的特点

2.1 声明式配置

Nix 使用声明式配置文件(如 configuration.nixshell.nix)定义系统或项目环境。通过这个文件,用户可以描述需要的软件包、依赖和设置。Nix 会解析并自动创建与配置相符的环境。这样可以极大减少配置出错的风险。

2.2 软件环境隔离

Nix 使用独立的构建环境,确保每个软件包及其依赖的隔离性。每个软件包安装在一个唯一的目录下(通常是 /nix/store),不会相互干扰。这种隔离避免了传统包管理器常见的“依赖地狱”(dependency hell)问题,即不同软件包对同一依赖库的版本冲突问题。

2.3 可重复性和可再现性

Nix 保证了构建过程的可重复性,即同样的配置和依赖会始终生成相同的结果。对于开发者来说,无论是搭建本地开发环境,还是在 CI 系统中进行部署测试,都可以确保在不同机器上生成一致的结果。

2.4 回滚与历史追踪

Nix 支持环境的版本控制功能,允许用户轻松回滚到以前的配置。无论是单个软件包的更新出错,还是系统配置有问题,用户都可以快速恢复到之前的版本。

2.5 多用户安全支持

Nix 设计为多用户友好,每个用户可以独立管理自己的环境,而不干扰系统或其他用户。它确保了每个用户的权限隔离,不必担心用户安装的软件包会影响到全局环境。

3. Nix 的核心优势

Nix 工具的设计和理念解决了传统包管理器的一些核心问题,尤其在复杂开发环境中的一些痛点:

3.1 依赖管理

传统包管理器有时会导致依赖冲突或版本不一致的情况。Nix 的唯一性和隔离机制确保了不同版本的依赖库可以共存,避免了依赖冲突。

3.2 可重复性构建

现代软件开发常常依赖于特定版本的工具链和依赖。Nix 提供了一种稳定的、可再现的构建环境,特别适合对环境要求苛刻的项目,如科研、数据分析或大型应用的持续集成系统。

3.3 灵活性

Nix 支持 Linux、macOS,甚至 Windows(通过 WSL),因此它适用于不同操作系统的开发人员。此外,它支持在多个项目中创建不同的隔离开发环境,使得同一台机器上能够并行开发多个具有不同依赖的项目。

4. 安装与使用

4.1 Nix 安装

在 Linux 和 macOS 上安装 Nix 非常简单。只需运行以下命令:

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

该命令会自动下载并安装 Nix,并将必要的环境变量配置到用户的 shell 中。安装完成后,可以通过重启终端来激活 Nix。

4.2 初始化开发环境

安装完成后,可以通过 nix-shell 来创建和使用隔离的开发环境。我们通过创建一个 shell.nix 文件来定义环境配置:

{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  buildInputs = [
    pkgs.git
    pkgs.nodejs
  ];
}

在该文件中,定义了两个依赖:gitnodejs。使用 nix-shell 进入环境:

nix-shell

此时,用户的 shell 环境将会包含指定的依赖工具,无需在系统全局安装。

4.3 管理软件包

Nix 可以轻松安装软件包,类似于其他包管理器的工作方式。例如,安装 vim

nix-env -iA nixpkgs.vim

其中 -iA 参数表示直接从 Nix 软件包仓库中安装特定的包。

要查看当前安装的软件包列表,可以使用:

nix-env -q

4.4 升级和回滚

Nix 允许随时升级环境中的软件包:

nix-env --upgrade

如果升级后环境出现问题,可以使用回滚命令恢复到之前的版本:

nix-env --rollback

4.5 使用 NixOS 系统

除了 Nix 包管理器,Nix 还拥有一个基于 Nix 工具的操作系统——NixOS。这是一个完全声明式的 Linux 发行版,用户可以通过配置文件精确描述操作系统的各个组件和服务。

5. Nix 与 NVM、Pyenv、Miniconda 的对比

在开发过程中,很多开发者会使用工具来管理特定编程语言的版本和依赖,如 nvm 用于 Node.js、pyenvminiconda 用于 Python。Nix 虽然是一个通用的包管理器,但在管理多语言开发环境时也具备类似功能。下面,我们对比一下 Nix 与这些工具的异同。

5.1 Nix 与 NVM(Node.js 版本管理)

相同点
  • 版本管理nvm 专注于管理不同版本的 Node.js,而 Nix 也可以通过声明式配置来指定需要的 Node.js 版本。两者都允许用户为不同项目指定不同的 Node.js 版本,从而避免版本冲突。
  • 隔离环境nvm 为每个 Node.js 版本提供了隔离的环境,用户可以在不同项目中使用不同版本的 Node.js,Nix 也具备同样的能力,可以通过 nix-shell 为每个项目创建独立的开发环境。
不同点
  • 通用性nvm 仅用于 Node.js 的版本管理,而 Nix 是通用的包管理器,除了 Node.js,Nix 还能管理各种其他编程语言及其依赖,甚至操作系统级别的工具和库。
  • 声明式 vs 命令式nvm 的配置是命令式的,用户需要手动执行命令来安装和切换 Node.js 版本。而 Nix 采用声明式配置文件(如 shell.nix),用户只需定义所需的 Node.js 版本,Nix 会自动处理其安装和依赖。

5.2 Nix 与 Pyenv、Miniconda(Python 版本管理)

Pyenv 对比
相同点
  • Python 版本管理pyenv 允许用户安装和切换多个 Python 版本。Nix 同样可以管理 Python 及其版本,通过 nix-shell 可以轻松为每个项目提供指定版本的 Python 环境。
  • 隔离环境pyenv 通过虚拟环境(如 pyenv-virtualenv 插件)提供 Python 依赖的隔离。Nix 提供类似的功能,在每个 nix-shell 会话中隔离不同项目的依赖,避免 Python 包冲突。
不同点
  • 通用性pyenv 只能管理 Python 版本,而 Nix 是通用的包管理器,可以同时管理多种语言及其依赖。
  • 声明式配置pyenv 的版本管理需要手动切换,而 Nix 通过声明式文件(如 shell.nix)定义 Python 版本和依赖,提供更自动化的方式,并且无需手动操作即可确保环境一致性。
  • 系统依赖管理pyenv 只关注 Python 语言本身,而 Nix 可以同时管理 Python 及其依赖的系统库(如 C/C++ 库)。
Miniconda 对比
相同点
  • 虚拟环境与依赖管理miniconda 和 Nix 都可以为不同项目创建独立的虚拟环境,安装特定版本的 Python 及依赖包。两者都可以为每个项目创建隔离的运行环境,确保环境的干净和一致性。
  • 跨平台支持miniconda 和 Nix 都支持在不同平台(如 Linux、macOS)上运行,并能跨平台管理软件包和环境。
不同点
  • 包管理模型miniconda 使用的是 conda 包管理系统,而 Nix 使用自己独特的 nixpkgs 仓库。conda 偏向于数据科学和科学计算,提供了很多专门为 Python 用户优化的库。Nix 则是通用的包管理器,涵盖了广泛的软件包和语言工具。
  • 声明式 vs 命令式minicondaconda 的使用是命令式的,用户需要手动创建环境并安装软件包。而 Nix 提供声明式的方式,可以通过配置文件完整定义项目的依赖和环境,使其更加易于自动化和复现。
  • 系统依赖的处理:与 Nix 一样,conda 也能处理某些系统级依赖,但是 Nix 在此方面更加灵活和广泛,支持几乎所有操作系统层面的库和工具。

5.3 总结对比

工具 支持语言 包管理方式 环境隔离 声明式配置 回滚与版本控制 系统依赖管理
Nix 多语言 声明式
NVM Node.js 命令式
Pyenv Python 命令式 是(插件)
Miniconda Python 命令式 部分支持

从上表可以看出,Nix 的核心优势在于它的通用性声明式配置。无论是对多语言开发环境的支持,还是对于依赖包和系统库的全面管理,Nix 提供了比专用语言管理器(如 nvmpyenv)更加广泛的功能。同时,Nix 的声明式模型确保了环境的一致性和可再现性,使其在复杂项目中具备独特的优势。

5. 结语

Nix 是一个功能强大且灵活的包管理器,它通过声明式的配置、隔离环境和版本控制等功能,为开发者提供了极大的便利和灵活性。无论是在单独管理软件包,还是为项目创建隔离开发环境,Nix 都提供了一种可重复、可靠且高效的解决方案。对于那些希望彻底摆脱依赖地狱和环境不一致问题的开发者,Nix 无疑是一个值得深入研究和使用的工具。

Nix算是docker的另一个简单化选择,当然它也可以通过docker安装和使用。声明式对于前段应该不陌生,那就是HTML,它就是一个声明式的界面定义,由浏览器根据它渲染,每次刷新都保持了很好的一致性。而这种一致性、可复现、易阅读将来肯定会取代很多编程工作,只需要描述一个清晰的需求,具体的实现让runtime去实现 - 满足这个需求即可,而不要教他一步步该怎么做-出了异常怎么恢复。