Skip to main content

NixOS 春节假期折腾之旅

· 7 min read
therainisme
快乐!

背景

在春节假期时,无意中浏览到了 ryan4yin 的博客,初次见识到了这个系统。我们早已习惯在 /etc 目录下与无数配置文件搏斗,在软件版本依赖的地狱中挣扎。当系统升级导致开发环境崩溃时,那种熟悉的恐惧感总会涌上心头。Docker 容器虽然提供了临时避难所,却始终治标不治本。

NixOS 让人强烈欲望入坑的特点

  • 用一份 /etc/nixos/configuration.nix 文件定义整个系统
  • 每次系统配置更新,都会提供 Generation 防止错误配置无法回退
  • 完全可复现的开发环境,只需要 git clone,不再需要 pacmanapt

万物之始

我们可以从 NixOS 官方下载 Minimal ISO image,在一台全新的机器上安装 NixOS。或是通过 nixos-infect 脚本,一键将非 NixOS 的系统转换成 NixOS。后者在阿里云 ECS 上测试是可用的。

非常非常 Easy 的配置文件 /etc/nixos/configuration.nix,在下面的配置中,我们指定了 root 用户的 authorizedKeys 以及密码,配置了 ssh-server,配置了 vscode-server,主机名等信息都可以通过该配置文件完成。当把下面的文件写入后,只需要运行 nixos-rebuild switch,一切都完成了。

我的服务器通过手动划分磁盘,挂载 btrfs 后,执行 nixos-install 脚本安装。更详细的安装教程可以参考这篇博客:从 0 实现全集梦中情 OS。如果对于操作没有那么熟悉,可以现在虚拟机中尝试,后续想部署到服务器上,只需要复制配置文件到服务器,执行 nixos-rebuild switch,就都一模一样了。

# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).

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

{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
# vscode server
(fetchTarball {
url = "https://github.yuuza.net/nix-community/nixos-vscode-server/tarball/master";
sha256 = "09j4kvsxw1d5dvnhbsgih0icbrxqv90nzf0b589rb5z6gnzwjnqf";
})
];

boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;

# Pick only one of the below networking options.
# networking.wireless.enable = true;
networking.networkmanager.enable = true;

# 配置时区等机器信息
time.timeZone = "Asia/Shanghai";
i18n.defaultLocale = "en_US.UTF-8";
networking.hostName = "hostname";

nixpkgs.config.allowUnfree = true;

# 安装的软件
environment.systemPackages = with pkgs; [
openssl
wget
curl
nano
tailscale
];
# 设置默认编辑器
environment.variables = {
EDITOR = "nano";
};

# 配置 OpenSSH 和 Tailscale
services.openssh.settings = {
PermitRootLogin = "yes";
PasswordAuthentication = true;
};

# 启动系统服务,类似 systemctl enable --now xxx
services.openssh.enable=true;
services.tailscale.enable = true;
services.vscode-server.enable = true;

# Root 用户的配置
users.users.root = {
openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC......tTMFP5y8v8= [email protected]"
];
# 这密码我随便写的
password = "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865";
};

system.stateVersion = "24.11";
}

开发环境配置(Devbox 与 Direnv)

在软件开发中,环境配置一直是令人头疼的难题。不同项目对编译器版本、依赖库、环境变量的差异化需求,常常导致"在我的机器上能运行"的经典问题。接下来将介绍基于 Devbox 和 Direnv 管理环境方案,通过两个典型 Go 项目案例,展示如何实现开发环境的精准控制。

准备事项

在所有例子之前,必须安装 devbox 和 direnv,同时给 IDE 装上支持 direnv 的插件。如果使用的是 NixOS,添加如下配置文件,并 nixos-rebuild switch

programs.direnv.enable = true;
environment.systemPackages = with pkgs; [
...
devbox
];

例子一:杂交的 Go 程序,开启 CGO 与 [email protected] 版本

需要编译使用 CGO 的 Go 程序,并链接 RocksDB v9.8.4 数据库。该场景的复杂性在于:

  • 必须启用 CGO 支持
  • 需要特定版本的 C 库(RocksDB)
  • 依赖 pkg-config 查找头文件路径

首先进入项目的根目录,执行:

# 初始化 Devbox 项目
devbox init

# 添加精确版本依赖
devbox add [email protected] # 指定 RocksDB 版本,不指定默认 @latest
devbox add pkg-config
devbox add gcc

# 生成 Direnv 配置
devbox generate direnv

此时打开 shell,输入 pkg-config --cflags --libs rocksdb 所有环境都已经配置好了,就这么简单。

$ pkg-config --cflags --libs rocksdb
-I/nix/store/l9i65cfgnxgrxlghxg792146w00kafcn-rocksdb-9.8.4/include -L/nix/store/l9i65cfgnxgrxlghxg792146w00kafcn-rocksdb-9.8.4/lib -lrocksdb

例子二:老旧的 Go 程序,必须使用 [email protected] 版本

首先进入项目的根目录,执行:

devbox init
devbox add [email protected] # 精确锁定 Go 版本
devbox generate direnv

此时打开 shell,执行以下步骤即可验证:

# 在项目目录内验证
$ go version
go version go1.20.3 linux/amd64

# 查看环境隔离效果
$ which go
/home/user/.devbox/nix/profile/default/bin/go

更多杂项配置

TODO

Nixpkg 相关资料

  1. https://search.nixos.org/options 搜索 /etc/nixos/configuration.nix 文件的配置写法,例如安装 docker,根据它的描述,只需要添加一行即可:virtualisation.docker.enable = true;
  2. https://search.nixos.org/packages 相关 nixpkgs 的搜索,只要包不是离奇的冷门,都能找到,不过找不到旧版本的包。比如说 Go 的 1.20 版本无法在 24.11 里找到。
  3. https://www.nixhub.io/ Devbox 的相关网站,可以找到最新的包和历史所有包。例如 Go 的 1.20 版本在这里

Devbox 常用命令

  • devbox init: 为项目初始化 devbox, 运行后项目目录下会出现 devbox.json 文件,可以直接在文件中添加要使用的软件包,也可以像 npm 之类的包管理器一样使用 devbox add 添加软件包。
  • devbox add: 添加软件包,后面可以跟有 @xxx 指定版本号,如 devbox add [email protected]
  • dev search: 搜索软件包
  • dev rm: 删除软件包
  • devbox generate direnv: 自动为 direnv 生成 .envrc 文件,安装配置好后会自动载入环境。
  • devbox shell: 手动进入环境终端
  • devbox run: 手动运行命令(在 devbox.jsonshell.scripts 字段下手动添加 script,类似 node 的 package.json 中的 scripts)