specialisation(特化/专精)是 NixOS 中一个非常强大但常被低估的功能。它允许你在同一个系统世代下,派生出多个具有不同配置变体的 " 平行世界 "。
通俗地讲,它就像是给系统配置开了 " 多分支 ",但这几个分支在一次构建中全部生成好了,已构建变体可直接激活,但内核、引导和某些驱动变更需要重启。
一、核心概念:什么是 Specialisation?#
通常,当你执行 nixos-rebuild switch 时,系统会构建当前 configuration.nix 的状态,并生成一个 Generation。
而 specialisation 允许你在当前配置的基础上,定义若干个子配置。这些子配置会继承基础配置的所有内容,并在此基础上覆盖或追加特定的设置。一次 rebuild 会同时生成基础配置和所有特化配置,它们共享同一个 Generation 编号。
二、为什么要用 Specialisation?#
想象以下场景:
- 你平时用核显办公,但偶尔需要插上独显打游戏或跑深度学习。
- 你平时需要防火墙和代理,但偶尔需要在本地测试网络服务,需要调整防火墙允许的测试端口。
- 你平时用 GNOME,但想偶尔尝鲜 Hyprland(分别定义桌面服务和软件集合)。
如果没有 specialisation,你只能每次修改配置文件然后重新 rebuild。
有了 specialisation,你可以把这些 " 偶尔用 " 的配置写成变体,开机时在 GRUB 菜单中直接选择进入,或者在运行中通过命令瞬间切换(部分配置可能需要重新登录)。
三、如何定义 Specialisation?#
在 configuration.nix 中,使用 specialisation.<name>.configuration 来定义。
{ config, pkgs, lib, ... }:
{
# ===== 基础配置(日常模式)=====
networking.firewall.enable = true;
services.desktopManager.gnome.enable = true;
environment.systemPackages = with pkgs; [ firefox git ];
# ===== 特化配置 1:游戏模式 =====
specialisation."gaming".configuration = {
# 按服务需要开放示例端口,避免为游戏直接关闭整个防火墙
networking.firewall.allowedUDPPorts = [ 27015 ];
# 安装 Steam 和显卡驱动相关工具
environment.systemPackages = with pkgs; [ steam mangohud gamemode ];
};
# ===== 特化配置 2:开发/调试模式 =====
specialisation."debug".configuration = {
# 启用更详细的内核日志
boot.kernelParams = [ "debug" ];
# 安装一堆调试工具
environment.systemPackages = with pkgs; [ gdb valgrind strace ltrace ];
};
}四、如何使用这些变体?#
构建好之后(sudo nixos-rebuild switch),你有三种方式使用它们:
1. 开机时在 GRUB 中选择
重启电脑,在 GRUB 菜单的 "NixOS - All configurations" 子菜单里,你会看到类似这样的选项:
NixOS Generation 105(默认基础配置)NixOS Generation 105 - gamingNixOS Generation 105 - debug
选择哪个就进入哪个环境。
2. 在运行中的系统里切换(无需重启)
如果你想从 " 日常模式 " 瞬间切到 " 游戏模式 ",可以运行:
sudo /nix/var/nix/profiles/system/specialisation/gaming/bin/switch-to-configuration test如果需从源配置重新求值/构建并激活指定变体,可使用本机支持的 rebuild 接口:
sudo nixos-rebuild test --specialisation gaming注意:这种热切换能生效的程度取决于配置内容。新闭包的软件路径和可热激活服务会切换,但已运行进程不自动换成新二进制,但涉及内核模块、显示管理器(如从 GNOME 切到 Hyprland)的改动,可能需要注销重新登录甚至重启才能完全应用。
3. 路径和辅助工具
官方模块文档使用 /run/current-system/specialisation/<name>/bin/switch-to-configuration test。从基础系统切换后,/run/current-system 可能指向变体,访问兄弟变体时使用仍指向基础世代的系统 profile 路径,或显式保存基础闭包路径。辅助工具可能依靠标记文件识别变体,其约定需按工具版本核实,原生特化并不自动保证 /etc/specialisation 标记。
4. 覆盖继承值
特化默认继承父配置,选项合并仍遵循模块系统规则。父子两边给布尔或字符串写不同的普通定义可能产生冲突;明确覆盖时使用 lib.mkForce,列表默认则往往追加。例如:
specialisation.minimal.configuration = {
services.desktopManager.gnome.enable = lib.mkForce false;
};inheritParentConfig = false 可以关闭父配置继承,但此时需要提供完整有效的系统配置,不等于进程、数据或硬件的隔离。
五、Specialisation 的优势与局限#
优势:
- 省时:一次构建,多套配置可用。
- 原子性:变体和基础配置绑定在同一个 Generation 中,回滚时一起回滚,不会出现配置版本错乱。
- 干净:不用为了偶尔用一次的软件而长期污染日常环境。
局限:
- 构建时间长:因为所有变体都要在一次
rebuild中构建出来,如果你的变体里包含大量重型软件(如 Steam),更新时会求值并确保各变体输出可用,能使用现有 store 结果或缓存时不必全部重新编译。 - 不能跨越硬件边界:特化配置是在同一个硬件系统上运行的,你不能用它来让同一份配置在两台不同的电脑上表现不同(那应该用 Flakes 的多个
nixosConfigurations来实现)。
总结#
specialisation 是 NixOS 声明式配置的优雅体现。它将 " 系统的多种运行姿态 " 固化到了配置文件中,让你可以通过简单的目录选择或开机引导,在不同的工作环境间按明确的激活与重启边界切换。
参考与延伸
根据技术笔记重新整理,示例使用通用名称。