[Share Experiences] 用 Nix 制作自定义的 live 镜像
Tofloor
poster avatar
SamLukeYes
deepin
2022-05-04 00:42
Author

之前发过一帖说要教大家用 Nix 制作自定义的 live 镜像。Nix 的优势我在上一个帖子已经说过了,主要就是能用很少的配置文件精确地定义整个 iso。其实 Nix 的很多用法我还没玩明白,不过如果只是要 DIY 一个 live 镜像的话,也不需要对 Nix 有很深的理解。

闲话少说,让我们开始吧like

1. 安装 Nix

在使用 Nix 之前,我们需要安装 Nix。NixOS 用户可以跳过这一步。

(想必 NixOS 用户也不需要我教吧joy

安装方式可以参考北外镜像站的使用帮助。如果你的发行版打包了 Nix,也可以考虑用包管理器进行安装。例如,Arch Linux 可以安装官方仓库中的 nix 软件包,并参考 Arch Wiki 进行配置。

2. 自定义 iso.nix

接下来就可以着手于 iso 的配置文件了。NixOS 的官方手册社区 wiki 对此的介绍都很简略。为了方便起见,下面的介绍以我自己的 live 镜像配置为例,大家可以在我写的配置文件的基础上进行自定义。

首先,将我的 live 镜像配置仓库克隆到本地。访问 GitHub 有困难的朋友可以将域名 github.com 改为 hub.fastgit.xyz,或者自己想别的办法,本帖不再赘述。

git clone https://github.com/SamLukeYes/my-livecd
cd my-livecd/

对 iso 文件的定制主要是在 iso.nix 中定义的。下面逐段介绍我在 iso.nix 中自定义的部分。如果想先体验构建 iso 的过程,请跳至第 3 节。


imports = [ ... ];

这一段的作用是导入其他配置文件,其中包含官方提供的配置文件,以及我自己写的额外配置。

是 NixOS 官方的 GNOME 版 live 镜像的配置文件,你也可以选择 KDE 版,或者直接从没有图形界面的 minimal 版从头开始定制。官方的 live 镜像配置都可以在这里找到。

的用途我也没完全搞清楚,反正是从 wiki 上复制过来的blush

如果你仔细看了 wiki,会发现上述两个路径开头的 nixpkgs 被我改成了 nixos。至于为什么,后续在第 3 节会讲到。

./override.nix 中定义的是一些我自行修改过的软件包,包括安装 Arch Linux 所需的全套工具 (官方 nixpkgs 中的版本基本上是用不了的) 以及 timeshift (尚未合入官方 nixpkgs)。如果确定不需要的话可以把这一行注释掉 (即在该行前加 #,取消注释就是去掉该行前的 #,后续不再赘述)。当然,由于 Nix 语言是惰性求值的,如果后续不调用自定义的软件包,不注释掉也不会有任何影响。

./pacman/init.nix 则是和 Arch Linux 安装工具相关的全套配置,不需要的话直接注释掉即可。


nix.binaryCaches = [ "${import ./mirror.nix}/nix-channels/store" ];

这一行定义的是 Nix Cache 的镜像站,具体内容参见 mirror.nix。这个配置影响的是 live 镜像中的配置,如果不在 live 镜像中使用 Nix 的话就不用管。

如果你启用了 Arch Linux 安装工具,那么需要注意的是 pacman 所用的镜像站也引用了 mirror.nix 中的设置。只想单独修改 Nix Cache 的话,只需把这一行的 ${import ./mirror.nix} 替换为镜像站的地址即可。


# boot.kernelPackages = pkgs.linuxPackages_latest;

这一行来源于上游仓库,我并没有测试过,用途应该是让 iso 使用最新的内核(当前为 5.17)。我选择了使用默认的内核,所以把这一行注释掉了。目前 nixos-21.11 的默认内核是 5.10,unstable 的默认内核是 5.15。


fonts.fonts = with pkgs; [ noto-fonts-cjk ];

这一段是用来指定字体的,我在这里只指定了用于显示中文的 cjk 字体,更多字体包可以在 https://search.nixos.org 查找。


#i18n.defaultLocale = "zh_CN.UTF-8";

将这一行取消注释后,iso 的图形界面会默认显示中文。但是,在虚拟机中测试时发现,取消注释后输入法就用不了了,咱也不知道是为什么tail


i18n.inputMethod = {
    enabled = "ibus";
    ibus.engines = with pkgs.ibus-engines; [
      libpinyin table table-chinese
    ];
};

这里定义了加入 iso 中的输入法。如果你不喜欢 ibus,也可以考虑参考上游仓库中的写法用 fcitx5。不过,要让 fcitx5 在 GNOME 上表现良好,可能需要额外的 GNOME 扩展(gnomeExtensions.kimpanel),或者你也可以考虑用 KDE。

需要注意的是,ibus 输入法和 GNOME 扩展都是需要在启动后手动启用的。应该也有默认启用的配置方法,但我懒得折腾了……反正又不是不能用joy


# security.doas.enable = true;

这同样是来自上游,但我没有采用的配置。BSD 用户大概比较喜欢用 doas,而不是 sudo。


services = {
    gnome = { ... };
    ...
};

core-utilities 是 GNOME 的全家桶,这里完全可以禁用掉,之后再缺什么补什么。

tracker-minerstracker 是 GNOME 的文件索引服务,感觉在 live 镜像中没什么用,但某些 GNOME 应用在禁用这两个服务的情况下会报错。

gvfs 是 nautilus、nemo 等文件管理器的网络文件夹、回收站等功能所需的服务。

至于注释掉的 xserver.excludePackages = [ pkgs.xterm ];,大概是之前听群里的大佬说这一行代码可以禁用 NixOS 默认自带的 xterm,但我放在这儿好像并没有什么卵用,所以暂且注释掉了tail


users.defaultUserShell = pkgs.fish;

如果你偏好的 shell 不是 bash,那么就可以在这里把登录 shell 换成 zsh、fish、xonsh 等。


environment = {
    shells = [ ... ];
    systemPackages = [ ... ];
};

刚才如果自定义了登录 shell,这里就要把它加入 shells,否则可能会出现一些预期之外的行为。在上述配置中没有提到的、需要单独安装的软件包,可以在 systemPackages 中声明。


isoImage.squashfsCompression = "zstd -Xcompression-level 6";

这里定义了 squashfs 的压缩方式。如果不加这一行的话,会默认用 xz,压缩后占用的空间会略小一些,但压缩的速度和启动 live 系统的速度都会慢很多。

3. 构建 iso

为了方便构建 iso,我已经写好了 makeiso.sh。不过,你可能需要根据你自己的环境对这个构建脚本进行些许修改。

脚本中的 CHANNEL 变量要设置为用于构建 iso 的 NixOS channel 目录。随后,NIX_PATH 变量中 nixos 的值会被设置为 $CHANNEL

上一节已经提到了,这里为什么要用自定义的 nixos,而不用默认就有的 nixpkgs 呢?因为在非 NixOS 的发行版中,nixpkgs 所指向的 channel 通常是用来在本机上安装 Nix 软件包的,即 nixpkgs-unstable。我还不太清楚 nixpkgs-unstable 和 nixos-unstable 这两个 channel 到底有多大的区别,但用来构建 live 系统的 channel 应该还是用 nixos 的比较好。更何况有的时候我可能想用 stable 的 channel,那就和平常用来装包的 channel 更加不一样了。因此,我选择了使用和包含默认值的 nixpkgs 不同的名称,以示区别。

如果要使用和我一样的配置,需要事先添加名为 nixos-unstable 的 channel。

nix-channel --add https://mirrors.bfsu.edu.cn/nix-channels/nixos-unstable
nix-channel --update

之后用 ls ~/.nix-defexpr/channels 命令就可以看到 nixos-unstable 文件夹了。

也可以选择 nixos-21.11 这个稳定的 channel,前提是不用我准备的那一套 Arch Linux 安装工具,因为我在打包 archlinux-keyring 的时候用了 unstable 的新特性。

在一切都准备就绪之后,就可以运行 makeiso.sh 了like

chmod +x makeiso.sh
./makeiso.sh

如果在这一步遇到了 segfault,可以将 makeiso.sh 中的 export GC_DONT_GC=1 一行取消注释,然后重新执行。

最终生成的 iso 位于 result 文件夹中。如果需要对生成的 iso 进行修改,只需要修改配置文件,再重新运行 makeiso.sh 即可。不过需要注意的是,多次反复执行构建 iso 的操作会占用大量硬盘空间。当空间占用过大时,可使用 nix-collect-garbage 命令释放空间。

Reply Favorite View the author
All Replies
enforcee
deepin
2022-05-04 02:29
#1

好神奇的东西

scream

Reply View the author
gfdgd_xi
deepin
Ecological co-builder
2022-05-04 18:21
#2

虽然我不懂,但我大受震撼

Reply View the author
风吹过的绿洲
deepin
2022-09-01 16:25
#3

做一个deepin的呗,到时候我来学习学习

Reply View the author