编程 NixOS 深度实战:从零构建可复现的声明式开发环境

2026-07-27 19:47:11 +0800 CST views 7

NixOS 深度实战:从零构建可复现的声明式开发环境

一、引言:为什么你的开发环境需要「版本控制」

每个程序员都经历过这样的噩梦:接手一个旧项目,文档写着「只需要 pip install -r requirements.txt」,结果跑起来满屏报错。你花了两天排查,发现是某个系统库的版本和文档描述的不一致。或者是换了台新电脑,从零搭建开发环境花了整整一周。

这不是个案。根据 2025 年 JetBrains 开发者生态调查,平均每个开发者每年要花费 73 小时 在环境配置问题上。这不是创造价值的时间,这是纯粹的浪费。

问题的根源在于:我们的代码有版本控制(Git),但运行环境没有。我们可以对任何一个 commit 进行「版本回退」,却无法对系统状态进行同样的操作。你无法 git checkout system_2024_01_01,你只能重装系统。

NixNixOS 正是为了解决这个根本性问题而生的。它们把版本控制的思想引入到了整个系统的层面——不是控制代码,而是控制环境。


二、Nix 是什么:从一个思想实验开始

2.1 传统包管理器的问题

在深入 Nix 之前,让我们先理解传统包管理器(如 apt、yum、pacman)的工作方式:

系统状态 = 初始状态 + 所有安装操作的总和

这带来了几个根本性问题:

  1. 不可逆性apt remove 可能会留下残留,或者误删了其他包依赖的库
  2. 版本冲突:两个包需要同一个库的不同版本,传统方案只能二选一
  3. 不可复现:「在我的机器上能跑」——因为每个人的安装历史不同
  4. 全局污染:所有用户共享同一个 PATH,库版本互相影响

2.2 Nix 的核心思想:函数式包管理

Nix 采用了完全不同的哲学。它的核心思想来自函数式编程:

新系统状态 = 函数(初始状态, 声明式描述)

具体来说,Nix 的设计基于三个核心原则:

1. 声明式而非命令式

你声明「我要 Python 3.11、Node.js 18、PostgreSQL 15」,而不是执行一串命令序列。

2. 不可变性

每一个包都被安装到一个唯一的路径,这个路径由其内容的哈希值决定。如果两个包的内容不同,它们的路径必然不同。这意味着:版本不会「覆盖」,只会「共存」。

3. 原子性

所有操作都是原子的。要么完全成功,要么完全回滚。不会留下半安装状态。

2.3 Nix Store:理解 Nix 的钥匙

理解 Nix 的关键在于理解 Nix Store/nix/store)。

在传统系统中,安装一个程序可能做这些事情:

1. 把二进制文件复制到 /usr/bin/program
2. 把配置文件复制到 /etc/program.conf
3. 创建用户 www-data
4. 添加 systemd 服务文件

如果第 3 步失败,你可能有部分安装残留,很难干净地回退。

在 Nix 中,这个过程完全不同:

/nix/store/gaga87z9hk1m2wz3xwqj5v2qwlv9d7a1-program/
├── bin/
│   └── program
├── etc/
│   └── program.conf
└── ...

每个包被安装到一个以内容哈希命名的唯一目录。所有依赖也通过同样的方式组织。关键点在于:

# 查看一个包在 store 中的路径
$ nix-store -q --tree $(which python3)
/nix/store/...-python3-3.11.5/

这个路径看起来很「丑」,但它保证了一件事:相同的内容,永远有相同的路径


三、Nix 语言:配置即代码

3.1 Nix 的配置语言

Nix 有自己的语言(就叫 Nix Language),用于描述包和配置。它的语法受到函数式语言的影响,带有 Haskell 和 Lisp 的影子。

# 基础数据结构
let
  name = "hello";
  version = "2.12.1";
in
rec {
  # 这是一个 attribute set,类似字典/对象
  myPackage = {
    # 字符串插值
    pname = "${name}-example";
    version = version;
    
    # 函数式风格的条件表达式
    meta = with lib; {
      description = "A ${name} example";
      platforms = platforms.all;
      license = licenses.mit;
    };
  };
}

3.2 基础语法速览

变量和 let 绑定:

let
  x = 1;
  y = 2;
  # 可以引用之前的变量
  sum = x + y;
in
  sum  # 结果是 3

函数:

# 定义一个函数
add = x: y: x + y;

# 调用函数
add 1 2  # 结果是 3

# 柯里化
addFive = add 5;
addFive 10  # 结果是 15

attrset(属性集):

{
  name = "test";
  value = 42;
  nested = {
    foo = "bar";
  };
}
# 访问:nested.foo

继承(inherit):

let
  x = 1;
  y = 2;
in {
  inherit x y;
  z = 3;
}
# 结果是 { x = 1; y = 2; z = 3; }

3.3 derivation:Nix 的核心概念

Derivation(派生)是 Nix 中最核心的概念。你可以把它理解为「如何构建一个包」的描述。

# 一个简单的 derivation
{ stdenv, fetchurl }:

stdenv.mkDerivation rec {
  pname = "hello";
  version = "2.12.1";
  
  # 从哪里获取源码
  src = fetchurl {
    url = "https://ftp.gnu.org/gnu/hello/hello-${version}.tar.gz";
    sha256 = "0x123...";
  };
  
  # 构建步骤
  buildPhase = ''
    ./configure --prefix=$out
    make
  '';
  
  installPhase = ''
    make install
  '';
}

当你运行 nix-build 时,Nix 会:

  1. 计算这个 derivation 的输出路径(基于输入的哈希)
  2. 如果这个路径已存在于 store 中,跳过构建
  3. 否则,执行构建过程,将结果存入 store

四、NixOS:把 Nix 思想应用到整个操作系统

4.1 NixOS vs 普通 Linux

NixOS 是基于 Nix 包管理器的 Linux 发行版。它的核心理念是:整个操作系统都可以用 Nix 语言声明式描述

在传统 Linux 中,你可能会这样安装和配置 Nginx:

sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
# 编辑配置
sudo vim /etc/nginx/nginx.conf
sudo systemctl reload nginx

这些命令的执行顺序、历史状态都会影响最终结果。

在 NixOS 中,你只需要写一个配置文件:

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports = [
    # 包含硬件相关的配置
    ./hardware-configuration.nix
  ];

  # 定义系统包
  environment.systemPackages = with pkgs; [
    nginx
    vim
    git
  ];

  # 配置服务
  services.nginx = {
    enable = true;
    # 你可以直接写 Nginx 配置
    config = ''
      worker_processes auto;
      error_log /var/log/nginx/error.log;
      
      events {
        worker_connections 1024;
      }
      
      http {
        include /etc/nginx/mime.types;
        
        server {
          listen 80;
          server_name example.com;
          
          location / {
            root /var/www/html;
            index index.html;
          }
        }
      }
    '';
  };

  # 用户配置
  users.users.sagege = {
    isNormalUser = true;
    extraGroups = [ "wheel" "docker" ];
  };

  # 时区和语言
  time.timeZone = "Asia/Shanghai";
  i18n.defaultLocale = "zh_CN.UTF-8";

  # 启用 flakes 支持
  nix.settings.experimental-features = [ "nix-command" "flakes" ];

  # 应用配置并切换到新系统
  # $ sudo nixos-rebuild switch
}

然后运行:

sudo nixos-rebuild switch --upgrade

NixOS 会:

  1. 计算新系统配置与当前系统的差异
  2. 只构建/安装需要变更的部分
  3. 原子性地切换到新系统
  4. 如果新系统无法启动,自动回退到旧配置

4.2 NixOS 模块系统

NixOS 的强大之处在于其模块系统。每个服务(如 Nginx、PostgreSQL、Docker)都提供一个 Nix 模块,这些模块可以组合使用。

模块的基本结构:

{ config, lib, pkgs, ... }:

{
  # 选项声明
  options.services.myservice = {
    enable = lib.mkEnableOption "myservice";
    
    port = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = "Port to listen on";
    };
    
    dataDir = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/myservice";
      description = "Data directory";
    };
  };

  # 配置生成
  config = lib.mkIf config.services.myservice.enable {
    # 声明 systemd 服务
    systemd.services.myservice = {
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        ExecStart = "${pkgs.myservice}/bin/myservice --port ${toString config.services.myservice.port}";
      };
    };
    
    # 声明用户
    users.users.myservice = {
      isSystemUser = true;
      group = "myservice";
    };
    
    # 创建目录
    systemd.tmpfiles.rules = [
      "d ${config.services.myservice.dataDir} 0755 myservice myservice"
    ];
  };
}

模块系统的魔力在于可组合性。你可以在配置中随意引用其他模块的选项,Nix 会自动解决依赖关系。

4.3 系统回滚:NixOS 的杀手级特性

由于 NixOS 将所有系统状态都存储在 Nix Store 中,并且所有变更都是通过 generations(代际)管理的,你可以随时回滚到任何一个历史状态:

# 查看所有系统代际
$ nix-env --list-generations

  95   2024-01-15 10:23:45
  96   2024-01-16 14:30:22
  97   2024-01-17 09:15:33   ← 当前
  98   2024-01-18 11:45:12

# 回滚到上一个代际
$ sudo nixos-rebuild switch --rollback

# 切换到任意代际
$ sudo nixos-rebuild switch --generation 95

# 垃圾回收,清理旧代际(可选)
$ sudo nix-collect-garbage -d

这意味着你可以大胆尝试新配置——如果出了问题,一行命令就能回到昨天的状态。


五、Nix Flakes:下一代 Nix

5.1 什么是 Flakes

Flakes 是 Nix 2.0 引入的新功能,旨在解决 Nix 的一些长期痛点:

  1. 可复现的依赖:Flakes 锁定了所有输入的版本
  2. 清晰的接口:统一的 flake.nix 文件定义了输入和输出
  3. 更好的组合性:项目之间的依赖变得更加清晰

5.2 Flake 的基本结构

# flake.nix
{
  description = "My development environment";

  # 定义输入(依赖)
  inputs = {
    # nixpkgs 是主包仓库
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    
    # 添加 home-manager
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    
    # 可以添加任意 Git 仓库作为依赖
    my-overlay.url = "github:username/my-nix-overlay";
  };

  # 定义输出
  outputs = { self, nixpkgs, home-manager, ... }: {

    # NixOS 配置
    nixosConfigurations.myvm = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      
      # 传递给 NixOS 模块的参数
      specialArgs = { inherit inputs; };
      
      # 导入 NixOS 模块
      modules = [
        ./hosts/myvm/configuration.nix
        
        # 使用 overlay
        my-overlay.nixosModules.default
      ];
    };

    # 开发环境(无需重启系统)
    devShells.x86_64-linux.default =
      let
        pkgs = nixpkgs.legacyPackages.x86_64-linux;
      in
        pkgs.mkShell {
          # 在 shell 中可用的包
          buildInputs = with pkgs; [
            python311
            nodejs_20
            postgresql_15
            redis
            git
            vim
            ripgrep
            fd
          ];
          
          # Shell 钩子
          shellHook = ''
            echo "Development environment loaded"
            export PS1="(dev) $PS1"
          '';
        };

    # Home Manager 配置
    homeManagerModules.default = import ./home.nix;
  };
}

5.3 flake.lock:依赖锁定

每次你运行 nix flake update,Nix 会生成一个 flake.lock 文件,记录所有输入的具体版本:

{
  "nodes": {
    "nixpkgs": {
      "locked": {
        "owner": "NixOS",
        "repo": "nixpkgs",
        "rev": "a1b2c3d4e5f6...",
        "type": "github"
      },
      "original": {
        "owner": "NixOS",
        "repo": "nixpkgs",
        "branch": "nixos-unstable"
      }
    }
  }
}

这保证了:任何人在任何时间运行相同的 flake,都会得到完全相同的依赖版本

5.4 进入开发环境

# 进入定义好的开发环境
$ nix develop

# 或者指定一个 shell
$ nix develop .#devShells.x86_64-linux.mypython

# 查看环境中有什么
$ nix flake show

开发环境会自动设置 PATH 和所有依赖。你不需要安装任何东西——只需要运行一条命令。


六、Home Manager:用户级配置管理

6.1 什么是 Home Manager

Home Manager 管理的是用户级配置,而 NixOS 管理的是系统级配置

典型场景:你想让 Vim 使用特定的插件配置,但不想影响系统上的其他用户。Home Manager 就是来解决这个问题的。

6.2 Home Manager 配置示例

# home.nix
{ config, pkgs, ... }:

{
  # 导入 Home Manager 模块
  imports = [
    # 可以导入其他模块文件
    ./home/programs.nix
    ./home/services.nix
  ];

  # 用户级包(这些包只对这个用户可见)
  home.packages = with pkgs; [
    # 开发工具
    python311
    nodejs_20
    
    # 实用工具
    fzf          # 命令行模糊搜索
    exa          # ls 的替代品
    bat          # cat 的替代品
    fd           # find 的替代品
    ripgrep      # grep 的替代品
    delta         # git diff 的替代品
  ];

  # 程序配置
  programs = {
    # Git 配置
    git = {
      enable = true;
      userName = "Your Name";
      userEmail = "your.email@example.com";
      
      aliases = {
        co = "checkout";
        br = "branch";
        st = "status";
        lg = "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
      };
      
      extraConfig = {
        pull = "rebase";
        push = "default = current";
        core = {
          editor = "vim";
          autocrlf = "input";
        };
      };
    };

    # Zsh 配置
    zsh = {
      enable = true;
      
      # 插件
      plugins = with pkgs; [
        {
          name = "zsh-autosuggestions";
          src = pkgs.fetchFromGitHub {
            owner = "zsh-users";
            repo = "zsh-autosuggestions";
            rev = "v0.7.0";
            sha256 = "...";
          };
        }
        {
          name = "zsh-syntax-highlighting";
          src = pkgs.fetchFromGitHub {
            owner = "zsh-users";
            repo = "zsh-syntax-highlighting";
            rev = "0.7.1";
            sha256 = "...";
          };
        }
      ];
      
      profileExtra = ''
        # PATH 配置
        export PATH="$HOME/.local/bin:$PATH"
        
        # 启用历史共享(只在 NixOS 上有效)
        export HISTFILE=~/.zsh_history
        export SAVEHIST=100000
        setopt SHARE_HISTORY
        setopt HIST_IGNORE_DUPS
      '';
    };

    # Neovim 配置
    neovim = {
      enable = true;
      defaultEditor = true;
      
      # 使用包装器而非直接配置
      withNodeJs = true;
      withPython3 = true;
      
      plugins = with pkgs.vimPlugins; [
        # 包管理器
        vim-plug
        
        # 基础体验
        coc.nvim           # LSP 客户端
        nerdtree           # 文件树
        fzf-vim            # 模糊搜索
        
        # 代码补全和语言支持
        vim-go             # Go 支持
        ale                # 异步语法检查
        
        # 外观
        dracula-pro
        vim-devicons       # 文件图标
      ];
    };
  };

  # 服务(后台进程)
  services = {
    # GnuPG agent 转发(用于 SSH)
    gpg-agent = {
      enable = true;
      enableSshSupport = true;
    };
    
    # 自动备份配置到 Git
    chezmoi = {
      enable = true;
      apply = {
        package = pkgs.chezmoi;
      };
    };
  };

  # XDG 目录配置
  xdg.configFile = {
    # 符号链接到 repo 中的配置文件
    "kitty" = {
      source = ./dotfiles/kitty;
      target = "kitty";
    };
    "alacritty" = {
      source = ./dotfiles/alacritty;
    };
  };

  # Home Manager 会话变量
  home.sessionVariables = {
    EDITOR = "nvim";
    VISUAL = "nvim";
    LANG = "zh_CN.UTF-8";
  };

  # Programs that need special initialization
  home.activation = {
    linkDotfiles = config.lib.dag.entryAfter ["writeBoundary"] ''
      # 在切换配置时运行的脚本
      $DRY_RUN_CMD ln -sf ${./dotfiles} $HOME/.dotfiles 2>/dev/null || true
    '';
  };
}

6.3 应用 Home Manager 配置

# 从 flake 应用
$ nix run github:nix-community/home-manager -- switch --flake .#youruser

# 或者单独管理 home-manager
$ home-manager switch --file ./home.nix

七、实战:从零搭建 NixOS 开发环境

7.1 安装 NixOS

NixOS 支持多种安装方式。推荐使用最小化 ISO:

# 下载 ISO
wget https://channels.nixos.org/nixos-24.05/latest-nixos-minimal-x86_64-linux.iso

# 创建虚拟机或烧录到 USB
dd if=nixos.iso of=/dev/sdX bs=4M status=progress

启动后,你会有一个最小化的 CLI 环境。接下来的配置都可以通过 Nix 完成。

7.2 分区方案

# 查看磁盘
lsblk

# 分区(例如 /dev/sda)
parted /dev/sda -- mklabel gpt
parted /dev/sda -- mkpart primary 512MiB -8GiB      # boot 分区 (FAT32)
parted /dev/sda -- mkpart primary linux-swap -8GiB 100%  # swap
parted /dev/sda -- mkpart primary ext4 -8GiB -8GiB   # root 分区

# 格式化
mkfs.fat -F 32 /dev/sda1
mkswap /dev/sda2
mkfs.ext4 -L nixos /dev/sda3

# 挂载
mount /dev/disk/by-label/nixos /mnt
mkdir -p /mnt/boot
mount /dev/sda1 /mnt/boot
swapon /dev/sda2

7.3 生成初始配置

# 生成初始 NixOS 配置
nixos-generate-config --root /mnt

# 查看生成的文件
ls /mnt/etc/nixos/
# hardware-configuration.nix  ← 硬件相关(不要手动编辑)
# configuration.nix           ← 主配置文件

7.4 编写完整配置

# /mnt/etc/nixos/configuration.nix
{ config, pkgs, inputs, ... }:

{
  imports = [
    ./hardware-configuration.nix
  ];

  # ==================== 基础配置 ====================
  networking.hostName = "devbox";
  
  # 时区和国际化
  time.timeZone = "Asia/Shanghai";
  i18n.defaultLocale = "zh_CN.UTF-8";
  i18n.extraLocaleSettings = {
    LC_TIME = "zh_CN.UTF-8";
    LC_MONETARY = "zh_CN.UTF-8";
  };

  # ==================== 用户配置 ====================
  users.users.sagege = {
    name = "sagege";
    isNormalUser = true;
    description = "Developer";
    extraGroups = [
      "wheel"      # sudo 权限
      "docker"    # Docker 支持
      "libvirtd"  # 虚拟机
    ];
    packages = with pkgs; [];  # 用户级包由 home-manager 管理
  };

  # ==================== 启动引导 ====================
  boot.loader.grub = {
    enable = true;
    device = "/dev/sda";
    efiSupport = true;
    efiInstallAsRemovable = true;
    configurationLimit = 10;  # 保留最近 10 个代际的启动项
  };

  # ==================== 文件系统 ====================
  fileSystems = {
    "/" = {
      device = "/dev/disk/by-label/nixos";
      fsType = "ext4";
    };
    "/boot" = {
      device = "/dev/sda1";
      fsType = "vfat";
    };
  };

  swapDevices = [
    { device = "/dev/sda2"; }
  ];

  # ==================== 网络 ====================
  networking.networkmanager.enable = true;
  networking.firewall.enable = true;
  networking.firewall.allowedTCPPorts = [ 22 80 443 ];

  # ==================== 系统包 ====================
  environment.systemPackages = with pkgs; [
    # 基础工具
    git
    curl
    wget
    vim
    htop
    tree
    jq
    yq
    ripgrep
    fd
    fzf
    bat
    exa
    
    # 网络工具
    iproute2
    nettools
    dnsutils
    nmap
    
    # 容器
    docker
    docker-compose
    
    # 虚拟化
    virt-manager
    qemu_kvm
    
    # 字体
    (nerdfonts.override { fonts = [ "JetBrains" "FiraCode" "NerdFontsSymbolsOnly" ]; })
  ];

  # ==================== 服务配置 ====================
  services = {
    # Docker
    docker.enableNvidia = false;  # 如果有 NVIDIA 显卡,设为 true
    
    # SSH
    openssh = {
      enable = true;
      settings = {
        PermitRootLogin = "no";
        PasswordAuthentication = false;
      };
    };
    
    # Tailscale(异地组网)
    tailscale = {
      enable = true;
      useRoutingFeatures = "client";
    };
    
    # 打印服务(如果有打印机)
    printing.enable = true;
    
    # 增亮支持
    brightnessctl.enable = true;
  };

  # ==================== 桌面环境(可选)====================
  # 如果需要 GUI,取消下面的注释
  
  # services.xserver = {
  #   enable = true;
  #   displayManager.gdm.enable = true;
  #   desktopManager.gnome.enable = true;
  #   
  #   # GPU 驱动
  #   hardware.graphics.enable = true;
  #   hardware.opengl.enable = true;
  # };
  
  # ==================== Flakes 配置 ====================
  nix.settings = {
    experimental-features = [ "nix-command" "flakes" ];
    auto-optimise-store = true;
    builders = [
      # 远程构建(可选,加速多平台构建)
      # "ssh://user@build-server x86_64-linux /nix/store - - root@x86_64-linux"
    ];
  };

  # ==================== 系统优化 ====================
  
  # 透明大页支持
  boot.kernel.sysctl = {
    "vm.swappiness" = 10;
  };

  # ==================== 安全加固 ====================
  security = {
    # AppArmor
    apparmor.enable = true;
    
    # 随机化 MAC 地址
    randomizedMacAddress = true;
  };

  # ==================== 电源管理 ====================
  powerManagement = {
    enable = true;
    cpuFreqGovernor = "powersave";
  };

  # 声明式关机/重启
  system.switchControl.enable = true;
}

7.5 应用配置

# 构建并切换到新配置
sudo nixos-rebuild switch --flake /mnt/etc/nixos#

# 如果配置有问题,使用 --rollback 回退
sudo nixos-rebuild switch --rollback

# 升级到最新版本
sudo nixos-rebuild switch --flake .# --update-input nixpkgs

7.6 完整项目结构示例

一个典型的 NixOS 项目结构:

~/nix-config/
├── flake.nix                    # Flake 定义
├── flake.lock                   # 依赖锁定
├── Makefile                     # 常用命令
│
├── # ──────────────────────────────────────
├── hosts/                       # 机器特定配置
│   ├── default.nix              # 默认机器
│   ├── devbox/                  
│   │   └── configuration.nix   # 开发机配置
│   └── server/
│       └── configuration.nix    # 服务器配置
│
├── # ──────────────────────────────────────
├── modules/                     # 可复用的模块
│   ├── gaming.nix               # 游戏配置
│   ├── development.nix         # 开发环境
│   ├── media.nix               # 媒体工具
│   └── security.nix            # 安全加固
│
├── # ──────────────────────────────────────
├── home/                        # Home Manager 配置
│   ├── default.nix             # 默认用户配置
│   ├── sagege/
│   │   ├── default.nix
│   │   ├── programs.nix        # 程序配置
│   │   └── services.nix        # 服务配置
│   └── dotfiles/               # 符号链接的配置文件
│       ├── gitconfig
│       ├── vimrc
│       └── alacritty.toml
│
└── # ──────────────────────────────────────
├── pkgs/                        # 自定义包
│   └── my-tool/default.nix
│
└── scripts/                     # 辅助脚本
    └── backup.sh

Makefile 示例:

.PHONY: switch test build switch-home clean

# 切换到当前主机配置
switch:
	sudo nixos-rebuild switch --flake .#$(hostname)

# 测试配置(不激活)
test:
	sudo nixos-rebuild test --flake .#$(hostname)

# 构建配置
build:
	sudo nixos-rebuild build --flake .#$(hostname)

# 切换 Home Manager 配置
switch-home:
	home-manager switch --flake .#sagege

# 垃圾回收
clean:
	sudo nix-collect-garbage -d
	nix-collect-garbage -d

# 更新依赖
update:
	nix flake update

# 查看差异
diff:
	nixos-rebuild diff --flake .#$(hostname)

八、性能优化与生产实践

8.1 Nix Store 垃圾回收

Nix 会保留所有历史包,时间久了会占用大量空间。

# 查看 store 使用情况
nix-store --query --requisites /run/current-system | wc -l
du -sh /nix/store

# 收集垃圾(删除不再被任何配置引用的包)
sudo nix-collect-garbage

# 删除旧代际(保留最近的 3 个)
sudo nix-collect-garbage --delete-older-than 3d

# 完全清理(危险)
sudo nix-collect-garbage -d

8.2 并行构建

Nix 默认并行下载和构建:

# 设置并行数
nix.conf = {
  max-jobs = "auto";        # 自动检测 CPU 核心数
  cores = 0;                # 0 表示全部
  builders = 8;            # 远程构建器数量
};

8.3 Binary Cache

配置 binary cache 可以大幅加速部署,避免重复构建:

# 在 configuration.nix 中
nix.settings = {
  substituters = [
    "https://nix-community.cachix.org"
    "https://cache.nixos.org"
  ];
  trusted-public-keys = [
    "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
    "cache.nixos.org-1:6NCHdD59X4311h5AAg7amBXo1h0DH8fHkl9LWzNpzSs="
  ];
};

8.4 远程构建

对于 ARM 设备(如树莓派)或资源有限的机器,可以利用远程构建:

# 添加构建器
nix config set experimental-features 'nix-command flakes'

# 通过 SSH 添加远程构建器
ssh user@build-server nix store set-resolution --help

# 或者在 configuration.nix 中配置
nix.settings.builders = [
  "ssh://user@build-server x86_64-linux /nix/store - - root@x86_64-linux"
];

8.5 诊断工具

# 查看包的依赖图
nix-store --query --graph $(which python3) | dot -Tpng > deps.png

# 检查包完整性
nix-store --verify --check-contents

# 查看构建时间
nix-instantiate --parse --eval -A config.systemd.services.python3Unit.startTime

九、Nix 与其他工具的对比

9.1 Nix vs Docker

维度NixDocker
粒度包级别镜像级别
共享相同包只存储一份层叠
可调试性天然可调试需要进入容器
状态持久可变状态容器销毁即丢失
系统级管理整个系统应用容器化
学习曲线陡峭平缓

结论:Nix 适合管理整个开发/生产环境,Docker 适合打包和分发应用。两者可以结合使用。

9.2 Nix vs Homebrew/Linuxbrew

Homebrew 是优秀的 macOS 包管理器,但:

  • 只管理用户级包
  • 不支持声明式配置
  • 不能保证可复现性
  • 没有系统级管理能力

9.3 Nix vs Ansible/Puppet

Ansible 和 Puppet 也是声明式配置工具,但:

  • 它们描述的是期望状态,而不是如何到达状态
  • Nix 在包级别实现声明式,Ansible 在系统配置级别
  • Nix 的原子性更强(通过 generations)
  • Ansible 需要 Python 运行时,Nix 独立

十、NixOS 生态全景

10.1 常用资源

  • NixOS 官网:https://nixos.org
  • Nixpkgs 仓库:https://github.com/NixOS/nixpkgs(超过 80,000 个包)
  • NixOS Wiki:https://nixos.wiki
  • Nix 社区:https://nix-community.github.io

10.2 重要生态项目

项目用途
home-manager用户级配置管理
nix-darwin在 macOS 上使用 Nix
devshell项目级开发环境
cachix团队 binary cache 服务
fenix自动更新的 Rust 工具链
flake-partsFlake 模块化框架
treefmt统一代码格式化

10.3 公司使用案例

越来越多的公司采用 Nix/NixOS:

  • Andreessen Horowitz (a16z):内部开发环境
  • Devsnek:Gecko 浏览器开发
  • Spectral Logic:硬件驱动开发
  • Tweag:Nix 咨询和服务

十一、常见问题与解决方案

11.1 Q: Nix 看起来很复杂,值得学习吗?

A: 如果你满足以下任一条件,答案是肯定的:

  • 经常在不同机器间切换开发环境
  • 需要维护多个项目,每个项目依赖不同版本的语言/工具
  • 对系统可复现有强烈需求
  • 想要「一次配置,永久可复现」

11.2 Q: 遇到问题了怎么办?

A: 按优先级:

  1. NixOS Wiki:https://nixos.wiki
  2. Search Engines:搜索 site:nixos.org <问题>
  3. GitHub Issues:在 nixpkgs 或相关项目中搜索
  4. Discord/Spectrum:Nix 社区实时讨论
  5. r/NixOS:Reddit 社区

11.3 Q: 如何学习 Nix?

推荐学习路径:

  1. 基础:Nix 语言语法(参考官方 Tour)
  2. 包管理:nix-envnix-shell
  3. NixOS:configuration.nix 基础
  4. Flakes:flake.nixnix develop
  5. Home Manager:用户配置管理
  6. 高级:自定义包、模块开发

11.4 Q: Flakes 还是传统 Nix?

答案:使用 Flakes

Flakes 是未来方向,所有新项目都应该用 Flakes。虽然官方还在讨论稳定性,但实验功能已经足够稳定。


十二、总结与展望

12.1 Nix/NixOS 的核心价值

  1. 可复现性:相同的配置 = 相同的环境
  2. 原子性:升级/回滚无忧
  3. 声明式:配置即代码,版本可控
  4. 隔离性:多版本共存,无冲突
  5. 可追溯:每次变更都有记录

12.2 适用场景

强烈推荐

  • 个人开发者多设备环境管理
  • 开发团队标准化环境
  • CI/CD 环境一致性
  • 追求可复现性的任何场景

谨慎使用

  • 桌面游戏玩家(游戏反作弊兼容性问题)
  • 需要最新软件的用户(Nixpkgs 更新延迟)
  • 对 CLI 不熟悉的用户

12.3 未来展望

Nix/NixOS 正在快速发展:

  • Nix 2.0+:更好的错误信息、更快的解析速度
  • Flakes 稳定化:2026 年有望进入稳定版
  • 更好的 IDE 支持:Helix、Neovim、VS Code 插件成熟
  • 企业采用:更多公司开始评估和使用
  • 生态扩张:更多语言特定工具链集成

12.4 给新手的建议

  1. 从小处开始:先在现有系统用 nix-shell,不要一开始就装 NixOS
  2. 使用 Flakes:跳过传统 Nix,从 Flakes 开始
  3. 参考他人配置:GitHub 上有大量开源 NixOS 配置
  4. 理解核心概念:derivation、store、generation
  5. 保持耐心:学习曲线陡峭,但值得

附录:快速参考

常用命令速查

# 包管理
nix-env -iA nixpkgs.vim           # 安装包
nix-env -e vim                     # 卸载包
nix-env -q                          # 列出已安装

# Shell 环境
nix-shell -p python311             # 进入带 python 的 shell
nix develop                         # Flakes: 进入开发环境

# NixOS
sudo nixos-rebuild switch          # 切换配置
sudo nixos-rebuild switch --rollback # 回退
nixos-option services.sshd.enable  # 查看选项

# 清理
nix-collect-garbage                 # 垃圾回收
nix-store --gc                      # 清理 store

# 信息
nix-instantiate --eval -A '<nixpkgs>'{}
nix-info -m                         # 系统信息

Flake 常用命令

nix flake init                     # 创建新 flake
nix flake update                   # 更新依赖
nix flake show                     # 查看 flake 输出
nix flake check                    # 检查 flake
nix develop                        # 进入开发环境
nix build                          # 构建

作者:程序员茄子
发布日期:2026-07-27
标签:NixOS|Nix|Flakes|Home Manager|声明式配置|可复现构建|开发环境
关键字:NixOS|Nix|Flakes|Home Manager|declarative-configuration|reproducible-build|development-environment|devops|infrastructure-as-code
摘要:深度解析 Nix/NixOS 的函数式包管理哲学,从 Nix Store 底层原理到 NixOS 模块系统,从 Flakes 到 Home Manager,配完整代码示例与生产部署指南。

推荐文章

程序员茄子在线接单