OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 019

Specialisation:一个世代的多个配置变体

在一个基础配置下声明变体,并区分运行时激活与重启生效。

所在专题NixOS 系统基础与配置 ↗
约 8 分钟阅读开始阅读

specialisation(特化/专精)是 NixOS 中一个非常强大但常被低估的功能。它允许你在同一个系统世代下,派生出多个具有不同配置变体的 " 平行世界 "。
通俗地讲,它就像是给系统配置开了 " 多分支 ",但这几个分支在一次构建中全部生成好了,已构建变体可直接激活,但内核、引导和某些驱动变更需要重启。


一、核心概念:什么是 Specialisation?#

通常,当你执行 nixos-rebuild switch 时,系统会构建当前 configuration.nix 的状态,并生成一个 Generation。
而 specialisation 允许你在当前配置的基础上,定义若干个子配置。这些子配置会继承基础配置的所有内容,并在此基础上覆盖或追加特定的设置。一次 rebuild 会同时生成基础配置和所有特化配置,它们共享同一个 Generation 编号。

二、为什么要用 Specialisation?#

想象以下场景:

  1. 你平时用核显办公,但偶尔需要插上独显打游戏或跑深度学习。
  2. 你平时需要防火墙和代理,但偶尔需要在本地测试网络服务,需要调整防火墙允许的测试端口。
  3. 你平时用 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 - gaming
  • NixOS 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 声明式配置的优雅体现。它将 " 系统的多种运行姿态 " 固化到了配置文件中,让你可以通过简单的目录选择或开机引导,在不同的工作环境间按明确的激活与重启边界切换。


参考与延伸

  1. NixOS 手册 ↗
  2. Nix 语言手册 ↗
  3. NixOS 26.05 specialisation 模块 ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

NixOS 系统基础与配置

  1. 01NixOS:声明式系统的基础
  2. 02安装 NixOS:介质、分区与初始配置
  3. 03NixOS 配置基础:选项与模块
  4. 04用 Flake 与 Home Manager 管理系统
  5. 05NixOS 命令行:新旧接口与日常维护
  6. 06NixOS 世代管理与垃圾回收
  7. 07Specialisation:一个世代的多个配置变体
  8. 08配置可重现,应用为什么还会“失忆”?
CONTINUE READING / 下一篇Nix 与 NixOS:存储、回滚和声明式思维

从 store、profile 与命令式工具理解 NixOS 的系统模型。