NixOS | 分布式构建

在 NixOS 中对某些包进行一些自定义修改时,如果当前 store 里没有可用的二进制结果(即没有缓存 / 没有从 binary cache 下载到),Nix 会走正常构建流程去生成它——这就会触发编译。而本地机器性能通常有限,这时候就需要用到分布式构建,这里记录一下 NixOS 分布式构建的配置和验证过程。

假设/先决条件

  • 在两台机器(远程和本地)上系统级安装NixOS;
  • 对远程机器高度信任;
  • 机器之间的 SSH 连接;
  • 对 NixOS 和 Nix 语言有一些经验。

配置过程

本地机器配置

因为两台机器之前是通过 SSH 连接,所以需要生成 SSH Key:

# ssh-keygen -f /root/.ssh/<name of ssh key file>

这个命令会在 /root/.ssh 目录下生成名为 <name of ssh key file> 的 SSH 公钥/私钥对,执行命令时只需一路回车使用默认值或留空即可。注意,不要为 SSH 密钥添加密码短语,因为这个连接需要无密码连接。

为了方便 SSH 连接,可以创建 SSH 配置文件 ~/.ssh/config

  Host <remote alias>
    HostName <remote ip>
    User <remote username>
    Port <remote port>
    IdentityFile /root/.ssh/<name of ssh key file>

也可以直接在 configuration.nix 中配置在 programs.ssh.extraConfig 中:

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

{
  #...

  # SSH configuration for distribute build
  programs.ssh.extraConfig = "
    Host <remote alias>
      HostName <remote ip>
      User <remote username>
      Port <remote port>
      IdentityFile /root/.ssh/<name of ssh key file>
  ";

  #...
}

其中:

  • Host <remote alias>:用于标识某个特定的配置,可随意设置;
  • HostName <remote ip>:远程机器的 IP 地址;
  • User <remote username>:用于 SSH 连接的用户名;
  • Port <remote port>:远程机器的 SSH 端口;
  • IdentityFile /root/.ssh/<name of ssh key file>:前面生成的 SSH 私钥路径。

然后开始编辑 /etc/nixos/configuration.nix 如下:

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

{
  #...

  # You can see the resulting builder-strings of this NixOS-configuration with "cat /etc/nix/machines".
  # These builder-strings are used by the Nix terminal tool, e.g.
  # when calling "nix build ...".
  nix.buildMachines = [{
    # Will be used to call "ssh builder" to connect to the builder machine.
    # The details of the connection (user, port, url etc.)
    # are taken from your "~/.ssh/config" file.
    hostName = "<remote username>@<remote alias>";
    # CPU architecture of the builder, and the operating system it runs.
    # Replace the line by the architecture of your builder, e.g.
    # - Normal Intel/AMD CPUs use "x86_64-linux"
    # - Raspberry Pi 4 and 5 use  "aarch64-linux"
    # - M1, M2, M3 ARM Macs use   "aarch64-darwin"
    # - Newer RISCV computers use "riscv64-linux"
    # See https://github.com/NixOS/nixpkgs/blob/nixos-unstable/lib/systems/flake-systems.nix
    # If your builder supports multiple architectures
    # (e.g. search for "binfmt" for emulation),
    # you can list them all, e.g. replace with
    # systems = ["x86_64-linux" "aarch64-linux" "riscv64-linux"];
    system = "x86_64-linux";
    # Nix custom ssh-variant that avoids lots of "trusted-users" settings pain
    protocol = "ssh-ng";
    # default is 1 but may keep the builder idle in between builds
    maxJobs = 3;
    # how fast is the builder compared to your local machine
    speedFactor = 2;
    supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
    mandatoryFeatures = [ ];
  }];
  # required, otherwise remote buildMachines above aren't used
  nix.distributedBuilds = true;
  # optional, useful when the builder has a faster internet connection than yours
  nix.settings = {
    builders-use-substitutes = true;
  };
  # Only use remote machine to build
  #nix.settings.max-jobs = 0;

  #...
}

nix.buildMachines 中需要注意的是,hostName<remote username>@<remote alias> 格式指定远程连接,<remote alias> 就是上方 SSH 配置中指定的别名,也可以直接填写 IP 和端口,即 <remote username>@<remote ip>:<remote port>,不过这样还需要单独通过 <sshKey> 指定 SSH 私钥路径。

另外,每个 builder 都声明了一组 supportedFeatures,如果 builder 缺少派生类的 requiredSystemFeatures 之一,它将被忽略。以下是 nixpkgs 中使用的一些功能:

  • kvm:在虚拟机内部构建的所有内容,例如 NixOS 测试;
  • nixos-test:机器可以运行 NixOS 测试;
  • big-parallel:kernel config、libreoffice、evolution、llvm 和 chromium;
  • benchmark:机器可以生成评估分数(意味着构建通常需要相同的时间)。

以及,如果不想使用本地机器进行构建,可以本地配置最大 job 数为 0 (nix.settings.max-jobs = 0;)。

远程机器配置

远程机器最好单独创建一个用户用于 SSH 连接,编辑远程机器的 /etc/nixos/configuration.nix 如下:

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

{
  #...

  # Define a user accout.
  users.users.<remote username> = {
      description = "NixOS distrubute builder"; # Can be anything
      isSystemUser = true;
      createHome = false;

      openssh.authorizedKeys.keys = [
	"the .pub ssh key from local machine"
      ];
      openssh.authorizedKeys.files = [
        "path to a copy of the .pub file"
      ];
      # choose one of this two options

      uid = 500;
      group = "<remote username>";
      useDefaultShell = true;
    };
  };
  users.groups.<remote username>= {
    gid = 500;
  };
  nix.settings.trusted-users = [ "<remote username>" ];

  # Enable the OpenSSH daemon.
  services.openssh.enable = true;

  #...
}

远程机器的配置比较简单,只是添加用户时需要注意将前面在本地机器中 ssh-keygen 生成的公钥 (<name of ssh key file>.pub) 内容粘贴在 openssh.authorizedKeys.keys 中,或者将公钥文件拷贝到远程机器中,然后将其路径填写在 openssh.authorizedKeys.files,这两种方式任选其一即可。

另外,需要注意不要忘记开启远程机器的 SSH 连接 (services.openssh.enable = true;)。

测试

为了确认配置是否有误,首先可以测试 SSH 连接是否正常,如下:

$ sudo nix store info --store ssh-ng://<remote username>@<remote alias>
Store URL: ssh-ng://
Version: 2.28.4
Trusted: 1

进一步,可以构建测试项目 hello,首先在远程机器上删除该软件包(如果已经有的话):

$ nix store delete /nix/store/*hello*
2 store paths deleted, 1.19 MiB freed

然后,在本地机器上开始执行构建:

$ nix build nixpkgs#hello -v --rebuild --max-jobs 0
checking outputs of '/nix/store/qa8is0vmvak3c5l0krb5zsmqpm0q1nd0-hello-2.12.1.drv' on 'ssh-ng://<remote name>@<remtoe alias>'...
copying path '/nix/store/pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz' from 'https://cache.nixos.org'...
copying 0 paths...
copying path '/nix/store/m1r53pnnm6hnjwyjmxska24y8amvlpjp-hello-2.12.1' from 'https://cache.nixos.org'...

在编译 log 中可以看到 on 'ssh-ng://<remote name>@<remtoe alias>'... 字样就说明构建执行在远程机器上,在构建完成后也可以在远程机器上看到构建结果:

$ ls /nix/store | grep hello
m1r53pnnm6hnjwyjmxska24y8amvlpjp-hello-2.12.1
pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz

参考

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇