---
myst:
  html_meta:
    "description lang=en": "Setting up distributed builds"
    "keywords": "Nix, builds, distribution, scaling"
---

(distributed-build-setup-tutorial)=
# 분산 빌드 설정하기

```{contributors}
:authors: tfc
:editors: fricklerhandwerk
```

Nix는 여러 대의 컴퓨터에 작업을 동시에 분산하여 빌드 속도를 높일 수 있습니다.

## 소개

이 튜토리얼에서는 별도의 빌드 머신을 설정하고 로컬 머신이 빌드를 해당 머신에 넘기도록 설정합니다.

### 무엇을 배우게 됩니까?

다음 방법을 배웁니다.
- 로컬 머신에서 원격 빌더에 접근해 원격 빌드를 수행할 새 사용자 만들기
- 지속 가능한 방식으로 원격 빌더 설정하기
- 원격 빌더의 연결과 인증 테스트하기
- 로컬 머신이 빌드를 자동으로 분산하도록 설정하기

### 무엇이 필요합니까?

- [Nix 언어](reading-nix-language)에 대한 이해
- [](module-system-tutorial)에 대한 이해

- *로컬 머신*(예시 호스트 이름: `localmachine`)

  다른 머신에 빌드를 분산하는, [Nix가 설치된](install-nix) 컴퓨터입니다.

- *원격 머신*(예시 호스트 이름: `remotemachine`)

  *로컬 머신*으로부터 빌드 작업을 받는, NixOS가 실행 중인 컴퓨터입니다. 원격 NixOS 시스템을 설정하려면 [](provisioning-remote-machines-tutorial)의 안내를 따르십시오.

### 얼마나 걸립니까?

- 25분

## SSH 키 쌍 만들기

*로컬 머신*의 Nix 데몬은 `root` 사용자로 실행되며 원격 머신에 자신을 인증하려면 *개인* 키 파일이 필요합니다. *원격 머신*이 *로컬 머신*을 식별하려면 *공개* 키가 필요합니다.

*로컬 머신*에서 `root`로 다음 명령을 실행하여 SSH 키 쌍을 만드십시오.

```shell-session
# ssh-keygen -f /root/.ssh/remotebuild
```

:::{note}
키 쌍 파일의 이름과 위치는 자유롭게 정할 수 있습니다.
:::

(set-up-remote-builder)=
## 원격 빌더 설정하기

*원격 머신*의 NixOS 설정 디렉터리에 `remote-builder.nix` 파일을 만드십시오.

```{code-block} nix
{
  users.users.remotebuild = {
    isSystemUser = true;
    group = "remotebuild";
    useDefaultShell = true;

    openssh.authorizedKeys.keyFiles = [ ./remotebuild.pub ];
  };

  users.groups.remotebuild = {};

  nix.settings.trusted-users = [ "remotebuild" ];
}
```

`remotebuild.pub` 파일을 이 디렉터리에 복사하십시오.

이 설정 모듈은 홈 디렉터리가 없는 새 사용자 `remotebuild`를 만듭니다. *로컬 머신*의 `root` 사용자는 앞에서 생성한 SSH 키를 사용하여 SSH로 원격 빌더에 로그인할 수 있게 됩니다.

새 NixOS 모듈을 *원격 머신*의 기존 설정에 추가하십시오.

```{code-block} nix
{
  imports = [
    ./remote-builder.nix
  ];

  # ...
}
```

root로 새 설정을 활성화하십시오.

```shell-session
nixos-rebuild switch --no-flake --target-host root@remotemachine
```

### 인증 테스트

SSH 연결과 인증이 제대로 작동하는지 확인하십시오. *로컬 머신*에서 `root`로 다음을 실행하십시오:

```shell-session
# ssh remotebuild@remotemachine -i /root/.ssh/remotebuild "echo hello"
hello
```

`hello` 메시지가 보이면 인증이 작동하는 것입니다.

이 테스트 로그인은 원격 빌더의 호스트 키를 로컬 머신의 `/root/.ssh/known_hosts` 파일에도 추가합니다. 이후 로그인할 때는 호스트 키 확인으로 중단되지 않습니다.

(set-up-distributed-builds)=
## 분산 빌드 설정하기

:::{note}
*로컬 머신*이 NixOS를 실행 중이라면 이 섹션을 건너뛰고 [모듈 옵션을 통해 Nix를 설정](distributed-builds-config-nixos)하십시오.
:::

`root`로 [Nix 설정 파일](https://nix.dev/manual/nix/2.23/command-ref/conf-file)에 다음을 추가하여 Nix가 원격 빌더를 사용하도록 설정하십시오:

```
# cat << EOF >> /etc/nix/nix.conf
builders = ssh-ng://remotebuild@remotebuilder $(nix-instantiate --eval -E builtins.currentSystem) /root/.ssh/remotemachine - - nixos-test,big-parallel,kvm
builders-use-substitutes = true
```

::::{dropdown} 자세한 설명
첫 번째 줄은 다음을 지정하여 원격 머신을 원격 빌더로 등록합니다.
- 프로토콜, 사용자, 호스트 이름
- *로컬 머신*의 [시스템 유형](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-system)

  이렇게 하면 해당 시스템 유형의 작업이 *원격 머신*에 위임됩니다.

- SSH 키의 위치
- [지원되는 시스템 기능](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-system-features) 목록

  컴파일러 빌드와 [NixOS VM 테스트](integration-testing-vms) 실행을 원격 머신에 위임하려면 반드시 이 목록을 지정해야 합니다.

자세한 내용은 [`builders` 설정에 대한 참조 문서](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-builders)를 참고하십시오.

두 번째 줄은 모든 원격 빌더가 *로컬 머신* 대신 자체 바이너리 캐시에서 의존성을 가져오도록 지시합니다. 이는 원격 빌더의 인터넷 연결이 로컬 머신의 인터넷 연결보다 느리지 않다고 가정합니다.
::::

이 설정을 활성화하려면 Nix 데몬을 재시작하십시오:

:::::{tab-set}
::::{tab-item} Linux
`systemd`를 사용하는 Linux에서는 `root`로 다음을 실행하십시오:

```shell-session
# systemctl restart nix-daemon.service
```
::::

::::{tab-item} macOS
macOS에서는 `root`로 다음을 실행하십시오:

```shell-session
# sudo launchctl stop org.nixos.nix-daemon
# sudo launchctl start org.nixos.nix-daemon
```
::::
:::::


(distributed-builds-config-nixos)=
:::::{admonition} NixOS

*로컬 머신*이 NixOS를 실행 중이라면 설정 디렉터리에 `distributed-builds.nix` 파일을 만드십시오:

```{code-block} nix
{ pkgs, ... }:
{
  nix.distributedBuilds = true;
  nix.settings.builders-use-substitutes = true;

  nix.buildMachines = [
    {
      hostName = "remotebuilder";
      sshUser = "remotebuild";
      sshKey = "/root/.ssh/remotebuild";
      system = pkgs.stdenv.hostPlatform.system;
      supportedFeatures = [ "nixos-test" "big-parallel" "kvm" ];
    }
  ];
}
```

::::{dropdown} 자세한 설명
이 설정 모듈은 분산 빌드를 활성화하고 다음을 지정하여 원격 빌더를 추가합니다:
- SSH 호스트 이름과 사용자 이름
- SSH 키의 위치
- 어떤 *로컬 머신*의 [시스템 유형](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-system)

  이렇게 하면 해당 시스템 유형의 작업이 *원격 머신*에 위임됩니다.

- [지원되는 시스템 기능](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-system-features) 목록

  컴파일러 빌드와 [NixOS VM 테스트](integration-testing-vms) 실행을 원격 머신에 위임하려면 반드시 이 목록을 지정해야 합니다.

자세한 내용은 [`nix.buildMachines`에 대한 NixOS 옵션 문서](https://search.nixos.org/options?query=nix.buildMachines)를 참조하십시오.

`builders-use-substitutes`는 모든 원격 빌더가 *로컬 머신* 대신 자체 바이너리 캐시에서 의존성을 가져오도록 지시합니다. 이는 원격 빌더의 인터넷 연결 속도가 로컬 머신의 인터넷 연결 속도 이상이라고 가정합니다.
::::

기존 머신 설정에 새 NixOS 모듈을 추가하십시오:

```{code-block} nix
{
  imports = [
    ./distributed-builds.nix
  ];

  # ...
}
```

`root` 권한으로 새 설정을 활성화하십시오:

```shell-session
# nixos-rebuild switch
```
:::::

## 분산 빌드 테스트하기

*로컬 머신*에서 새 derivation을 빌드해 보십시오:

```shell-session
$ nix-build --max-jobs 0 -E "$(cat << EOF
(import <nixpkgs> {}).writeText "test" "$(date)"
EOF
)"
this derivation will be built:
  /nix/store/9csjdxv6ir8ccnjl6ijs36izswjgchn0-test.drv
building '/nix/store/9csjdxv6ir8ccnjl6ijs36izswjgchn0-test.drv' on 'ssh://remotebuilder'...
copying 0 paths...
copying 1 paths...
copying path '/nix/store/hvj5vyg4723nly1qh5a8daifbi1yisb3-test' from 'ssh://remotebuilder'...
/nix/store/hvj5vyg4723nly1qh5a8daifbi1yisb3-test
```

결과 derivation은 현재 시스템 시간에 의존하므로 호출할 때마다 달라지며, 따라서 로컬 캐시에는 절대 존재할 수 없습니다. [`--max-jobs 0` 명령줄 인수](https://nix.dev/manual/nix/2.23/command-ref/conf-file#conf-max-jobs)는 Nix가 이를 원격 빌더에서 빌드하도록 강제합니다.

마지막 출력 줄에는 출력 경로가 포함되어 있으며, 이는 빌드 배포판이 예상대로 동작함을 나타냅니다.

## 원격 빌더 설정 최적화하기

병렬성을 극대화하고, 자동 가비지 컬렉션을 활성화하고, Nix 빌드가 모든 메모리를 소비하지 않도록 하려면 `remote-builder.nix` 설정 모듈에 다음 줄을 추가하십시오:

```{code-block} diff
 {
   users.users.remotebuild = {
     isNormalUser = true;
     createHome = false;
     group = "remotebuild";

     openssh.authorizedKeys.keyFiles = [ ./remotebuild.pub ];
   };

   users.groups.remotebuild = {};

-  nix.settings.trusted-users = [ "remotebuild" ];
+  nix = {
+    nrBuildUsers = 64;
+    settings = {
+      trusted-users = [ "remotebuild" ];
+
+      min-free = 10 * 1024 * 1024;
+      max-free = 200 * 1024 * 1024;

+      max-jobs = "auto";
+      cores = 0;
+    };
+  };

+  systemd.services.nix-daemon.serviceConfig = {
+    MemoryAccounting = true;
+    MemoryMax = "90%";
+    OOMScoreAdjust = 500;
+  };
}
```

:::{tip}
[`nix.settings`](https://search.nixos.org/options?show=nix.settings)에서 사용할 수 있는 옵션에 대한 자세한 내용은 [Nix 참조 매뉴얼](https://nix.dev/manual/nix/latest/command-ref/conf-file)을 참조하십시오.
:::

원격 빌더마다 성능 특성이 다를 수 있습니다. 각 `nix.buildMachines` 항목에 대해 원격 빌더별로 `maxJobs`, `speedFactor`, `supportedFeatures` 속성을 올바르게 설정하십시오. 이렇게 하면 *로컬 머신*의 Nix가 빌드를 최적의 방식으로 분산하는 데 도움이 됩니다.

:::{tip}
자세한 내용은 [`nix.buildMachines`에 대한 NixOS 옵션 문서](https://search.nixos.org/options?query=nix.buildMachines)를 참조하십시오.
:::

중간자 공격 시나리오로부터 빌드 배포판을 보호하려면 `nix.buildMachines.*.publicHostKey` 필드를 각 원격 빌더의 공개 호스트 키로 설정하십시오.

## 다음 단계

- 각 원격 빌더에서 [](custom-binary-cache)
- 스토어 객체를 바이너리 캐시에 업로드하기 위한 [](post-build-hooks)

여러 빌더를 설정하려면 각 원격 빌더에 대해 [](set-up-remote-builder) 섹션의 안내를 반복하십시오. 새 원격 빌더를 모두 [](set-up-distributed-builds) 섹션에 나온 `nix.buildMachines` 속성에 추가하십시오.

:::{tip}
외부 트래픽을 줄이려면 원격 빌드 머신이 [바이너리 캐시를 호스팅](setup-http-binary-cache)하도록 설정하고, 이를 [우선 바이너리 캐시](custom-binary-cache)로 사용하십시오.
:::

## 대안

- [nixbuild.net](https://nixbuild.net) - 서비스형 Nix 원격 빌더
- [Hercules CI](https://hercules-ci.com/) - 자동 빌드 배포판을 갖춘 지속적 통합
- [garnix](https://garnix.io/) - 빌드 배포판을 갖춘 호스팅형 지속적 통합

## 참고 자료

- [Nix 참조 매뉴얼: 분산 빌드 설정](https://nix.dev/manual/nix/latest/command-ref/conf-file#conf-builders)
