能聊一下NixOS吗

刚看到这个OS 主要特色是可以根据一个配置文件完全在另一台电脑上复刻出一个一模一样的定制系统?

对哒

推荐个博客:

那理论上大家可以分享各种自己配置好的文件,其他人拿来直接用就行了? 有这样的分享网站吗?

github

NixOS 官方已经将各种功能封装成了 service 或 module,你在配置里只需要比如:

{
  services.syncthing.enable = true;
}

就可以使用 syncthing,其他类推。还有很多人在 GitHub 分享自己的 module,你只要引用就可以了。

WSL 上配置 NixOS 的介绍有没有?

我也是最近刚入坑了这个系统,我浅谈一下我的理解:

核心目录 /nix/store 是由nix软件包管理器管理的依托答辩(雾

NixOS主打的是带有可解释性的重构建,即虽然快照可以保存一个系统某时刻的状态,但是对于怎样得到这个系统的过程无法描述,NixOS正在试图做到这一点。

/nix/store 会向 /etc /bin /run /var 等目录提供数万个甚至数十万个软链接,以让内核和程序以为一切都是正常的。(现在home-manager正试图将home目录也存到/nix/store这托答辩中,然后链接过去,当然绝大部分home目录还没有遭到“荼毒”)

我认为NixOS主要有三个亮点:

  1. 安全地滚动更新:如果这次生成的内容不对,可以重启选择上次的profile,毕竟每次生成的profile都是互相隔离的,彼此不知道对方的存在,(虽然它们都存在/nix/store这托答辩中)当然这是有代价的,每更新一次可能多占1-4G,nix会尽量复用已有的生成,但是不是全部;如果认为旧profile已经没有用了,可以进行垃圾清理

  2. 安全地隔离开发:nixos拒绝全局性的开发环境,例如gcc,虽然它自带,但是默认不链接到/run/current-system/sw/bin,必须开启一个临时性的nix-shell或者在某个文件夹中设置开发环境,然后nix才会帮你将gcc链接过来。当然这也是有代价的,譬如nix不允许任何pip install(可能也不允许npm install这种),需要装的包都必须声明在configuration.nix或者flake.nix中;而且进行开发的时候需要向该路径传递大量的环境变量指示各个依赖的库路径或者东西,学习成本是客观存在的

  3. 安全地多版本共存:由于/run/current-system/sw里的lib和share都是系统必要的,任何软件包依赖的lib和share都是链接到别的/nix/store/-name/lib 或者 share里面的,因此允许A包和B包分别依赖libXXX.1.so和libXXX.2.so,这是其他发行版通常做不到的

NixOS的缺点也很明显,就是学习成本:

  1. 文档客观上不齐全,学习曲线陡峭,学起来特别累;
  2. 像Emacs必须接触(并且稍微会一点)elisp一样,NixOSer必须稍微会一点Nix语言,甚至需要看一些nix源码;当nix的任何overlay都不提供某个包时,得学着自己打包;
  3. 社区支持较小,尽管nix的包和aur数量上差不多,但aur有高达万人以上的维护者,nix社区可能不超过两千人(估算);
7 个赞

你好我有个疑问一直想问一下,都说 nix 可以装同一个软件不同版本,例如 go1.20 和 go1.17,但是没有人说应该如何在系统里切换 go 的版本

假设你有两个开发文件夹,A 和 B,其中 A 使用 Go 1.20,B 使用 Go 1.18(在官方存储库中没有找到 Go 1.17,也许需要在其他overlay中搜索)。

你应该在 A 或 B 文件夹的根目录下有一个 shell.nix 或 flake.nix 文件,用于指示项目所依赖的所有开发环境以及相应的版本(我假设使用的是 flake.nix)。

  1. 当你首次切换到 A 或 B 目录时(假设使用 direnv),direnv 将自动安装相应的开发环境和版本。
  2. 现在计算机上已经安装了多个版本的 Go,比如 GO 1.20/1.18,假设它们的路径如下:
    1. /nix/store/s6d4alqs2iysn9f4k5z99xa7yn3h61a3-go-1.20
    2. /nix/store/x7n44lfys59k5ajj9w1fkxw5391cnn5v-go-1.18
  3. 此时你在任何目录(除了A和B)输入go,都会报找不到命令,因为它们不会默认链接到系统级别的可执行目录(在别的系统上是/usr/bin,在这里是/run/current-system/sw/bin)
  4. 你切换到A目录,direnv会自动export环境变量,现在你的which go应该绑定到了/nix/store/s6d4alqs2iysn9f4k5z99xa7yn3h61a3-go-1.20/bin/go
  5. 你切换到B目录,direnv会unset再export环境变量,现在你的which go应该绑定到了 /nix/store/x7n44lfys59k5ajj9w1fkxw5391cnn5v-go-1.18/bin/go

这些是我目前的理解,可能不一定完全准确,目前我是按照这样实践的。

2 个赞

感谢,解决了我一直以来的疑问

但是项目目录下指示的依赖是类似于 nix-shell 那样创建一个新的 shell 吗? 比如我只在依赖里声明 go,那我系统里的其他 cli tool 还能用吗,例如 rg, fd 等

ps:原谅我傻鸟了, export 的话我觉得应该不影响其他的东西吧(

nix-shell是额外声明环境变量,只做加法不做减法。只要是在/run/current-system/sw/bin里的都可用。 rg,fd得看你是怎么装的了,可能nix-env -iA装的在这里不能用,因为它们不会链接到系统级别的可执行目录?(我没用nix-env这种方式装过,不敢瞎说) 如果你是写在configuration.nix或者flake.nix里然后重建系统的,那肯定是默认能用的。

1 个赞

但 nix 这个语言本身确实有点不喜欢, 如果不是 guix 有开源限制的话,我应该会尝试下 guix 的。

对于一些硬编码了路径,又很新的软件,自己打包都很难,感觉目前都没找到什么好办法。比如一个 rust 的软件,包含有巨量的 git 依赖的时候,写起来都很麻烦,编译的时候也容易出现默名其妙的编不过去的情况。

4 个赞