初探Nix-02-基于Flake的系统配置

初探Nix-02-基于Flake的系统配置

上一次我们使用基于Flake的构建系统构建了一些程序,今天我们来亲手用Flake搭建我们的系统配置。

配置入口NixOS系统配置作为Flake输出函数的一部分导出,下面我们简单的编写一个OS配置的入口:

{

description = "Nix system configuration with a desktop environment";

inputs = {

nixpkgs = {

url = "github:nixos/nixpkgs?ref=nixos-unstable";

};

};

outputs = inputs@{ nixpkgs, ... }: {

nixosConfigurations = {

your-os-name = nixpkgs.lib.nixosSystem {

system = "x86_64-linux";

modules = [

./path/to/entry.nix

];

};

};

};

}现在我们来一步步解析这个入口,首先,我们的所有系统配置都位于Flake输出的nixosConfigurations,这个配置项是一个键值对结构体,键是我们系统的名字,值是系统配置,Nix提供了工具函数nixosSystem来帮助我们构建系统。

因为键值对可以容纳多个系统配置,如果我们在这里编写的系统配置多于一个,就需要在构建时指定系统名,为了简单考虑,我们在这里只构建一个系统配置。

我们直接将目光转移到nixosSystem内部,system代表该构建的目标,这个标志会传递给nixpkgs,帮助他找到符合当前架构和系统的的软件包集合。modules是系统配置真正的入口,如果你刚刚安装NixOS,那么你的/etc/nixos下往往会有configuration.nix文件,你可以直接把该文件路径加入modules中,来完成传统配置到Flake配置的迁移。

关于OS ModuleNix下面的模块化配置项很多,为了区分,我们将modules下的所有文件都称为OS Module,简单来说,他们和过去的configuration.nix别无二致,但因为有了Flake的加持,你可以声明式的管理软件源,修改OS Module的参数,以及复用别人的系统配置。

定义OS Module的方式有两种,分别是简化配置和完整配置,比如,我们需要启用wget包:

# 简化配置

{ pkgs, ... }:

{

environment.systemPackages = with pkgs; [

wget

];

}如果使用完整配置,我们的配置项应该写在config下:

{ pkgs, ... }:

{

config = {

environment.systemPackages = with pkgs; [

wget

];

};

}实际上,一个完整的OS Module应当有以下条目,简化模式只是省略了options部分,且允许不在config内就可以编写配置:

{ ... }:

{

imports = [

# 该模块的子模块

];

options = {

# 该模块的选项声明

};

config = {

# 该模块的选项定义,根据`options`中的条目输出的最终配置

};

}我们可以把上面wget的例子修改一下:

{ pkgs, lib, ... }:

let

cfg = config.modules.packages.wget;

inherit (lib) mkEnableOption mkIf;

in

{

options.modules.packages.wget = {

enable = mkEnableOption "Enable wget";

};

config = mkIf cfg.enable {

environment.systemPackages = with pkgs; [

wget

];

};

}这时,我们如果将该文件导入配置,则不会向系统中添加wget,要启用该模块,我们要在配置的其他位置调用:

{ ... }:

{

# ...

modules.packages.wget.enable = true;

# ...

}使用模块定义系统配置在讨论接下来的内容之前,我们要介绍一下如何查询NixOS的系统配置项,你可以访问NixOS Search来获取当前版本所有的系统配置。

进行系统配置是一个完全主观的活动,每个人的项目组织能力和偏好都各不相同,因此每个人的系统配置项目也各不相同,笔者在这里记录的是自己的系统配置法,我的个人系统配置位于DesseraNix,其中大部分基于完整的模块写法,将主要功能作为接口暴露给外部配置。

当然,尽管沉淀了将近半年的时间,我的配置也并非十分成熟,我也在持续不断的改进我的配置,但就目前来说,我们可以将系统配置拆分为几个部分:

硬件配置启动引导配置本地化服务软件包用户配置硬件配置首先,我建议各位先浏览一下NixOS-Hardware,如果有你的硬件配置,你完全可以直接引入,跳过硬件配置的步骤。

如果没有你的硬件,你也可以引入它common模块下的配置来快速搭建自己的硬件配置。

手动硬件配置主要关注处理器和显卡:

{ lib, config, ... }:

{

# ...

# INTEL CPU 微码

hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;

# AMD

hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;

# ...

}显卡驱动可以参考上面的NixOS-Hardware的配置,我们稍微简化一下(我们假定你在nixpkgs>24.05):

# intel

{ pkgs, ... }:

{

boot.initrd.kernelModules = [ "i915" ];

hardware.graphics.extraPackages = with pkgs; [

intel-vaapi-driver

intel-ocl

intel-media-driver

intel-compute-runtime

vpl-gpu-rt

];

hardware.graphics.extraPackages32 = with pkgs; [

driversi686Linux.intel-vaapi-driver

driversi686Linux.intel-media-driver

];

}# nvidia

{ pkgs, ... }:

{

services.xserver.videoDrivers = lib.mkDefault [ "nvidia" ];

hardware.nvidia =

{

modesetting.enable = lib.mkDefault true;

open = lib.mkIf (lib.versionAtLeast config.hardware.nvidia.package.version "555") true;

prime =

{

intelBusId = "PCI:0:2:0";

nvidiaBusId = "PCI:1:0:0";

};

};

}这里的注意事项是,prime条目内的两个BusId是要用户手动检测的,该条目会启用nvidia-prime来辅助进行显卡的切换,使用sudo lshw -c display来展示显卡信息。

显卡驱动配置项经过了一次API变动,如果你正在使用nixpkgs-24.05,请使用hardware.opengl,该条目的配置不在此处赘述。

启动引导配置引导配置位于boot下,hardware-configuration.nix提供的配置实际上非常详尽,这里展示以下我的配置:

{ pkgs, ... }:

{

boot = {

loader = {

grub = {

enable = true;

device = "nodev";

efiSupport = true;

useOSProber = true;

};

efi = {

canTouchEfiVariables = true;

efiSysMountPoint = "/boot";

};

};

initrd.availableKernelModules = [

"xhci_pci"

"thunderbolt"

"vmd"

"nvme"

"usb_storage"

"sd_mod"

];

kernelModules = [ "kvm-intel" ];

kernelPackages = pkgs.linuxPackages_latest;

kernelParams = [

"nowatchdog"

"quiet"

];

};

}这里主要解释useOSProber选项,这个选项会启用GRUB_DISABLE_OS_PROBER=false,如果你有双系统,该条目是必须的,因为它可以检测额外的Windows系统分区并添加到GRUB启动项中。

本地化本地化这个话题实际上可以分为两部分,分别是时区和Locale。

下面是一个本地化配置实例:

{ pkgs, ... }:

{

# 设置时区

time.timeZone = "Asia/Shanghai";

time.hardwareClockInLocalTime = true;

# 设置Locale

i18n = {

defaultLocale = "zh_CN.UTF-8";

};

}关于输入法和字体的话题,会和桌面环境一起讨论。

服务服务是一个相当巨大的话题,因为每个人都有他们自己的服务项,比如我需要运行学校指定的网络客户端来连接网络,还需要一些udev规则来让我能够连接开发板等等。

我们这里列出一些必须的服务项:

{ lib, pkgs, ... }:

{

hardware.bluetooth = {

enable = true;

powerOnBoot = true;

};

networking = {

hostName = "your_os_name";

useDHCP = lib.mkDefault true;

networkmanager.enable = true;

hosts = {

"199.232.96.133" = [ "raw.githubusercontent.com" ];

};

};

}这份配置定义了蓝牙和网络服务。

同样的,关于xserver,我们将之后讨论

软件包你可以在NixOS Search中查询软件包,或者使用NUR。

定义系统软件包有两种方式,一种是programs,一种是environment.systemPackages,前者是nixpkgs预定义的一些软件,他们往往有良好的配置接口,后者是用户主动安装的程序包,他们虽然也会提供override式的配置接口,但便利性较差。

{ pkgs, ... }:

{

# 通过 programs

programs = {

direnv = {

enable = true;

enableZshIntegration = true;

};

neovim = {

enable = true;

viAlias = true;

vimAlias = true;

};

};

# 通过 environment

environment.systemPackages = with pkgs; [

wget

fastfetch

];

}用户配置用户配置暴露于users,它可以配置整个系统中所有的普通用户:

{

pkgs,

...

}:

{

users = {

defaultUserShell = pkgs.zsh;

users = {

dessera = {

isNormalUser = true;

extraGroups = [

"wheel"

"networkmanager"

"video"

"audio"

];

};

};

};

}借助Home Manager,Nix有管理用户目录下配置文件的能力,有关用户配置管理和桌面环境,我们留到之后讨论。

相关推荐

为什么USB给手机锂电池充电时间长?
长文深挖RNA药物研发:ASO,siRNA傻傻分不清楚?医药新闻
css超出部分显示省略号

css超出部分显示省略号

📅 10-10 👁️ 5720