(post-build-hooks)=
# 빌드 후 훅 설정하기

```{contributors}
:authors: grahamc
```

이 가이드에서는 Nix [`post-build-hook`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-post-build-hook) 설정 옵션을 사용하여 빌드 결과를 [S3 호환 바이너리 캐시](https://nix.dev/manual/nix/2.22/store/types/s3-binary-cache-store)에 자동으로 업로드하는 방법을 설명합니다.

## 구현 시 주의 사항

이 예제는 간단하고 실제로 동작하지만, 모든 사용 사례에 적합하지는 않습니다.

빌드 후 훅 프로그램은 빌드가 실행될 때마다 그 뒤에 실행되며, 빌드 루프를 차단합니다. 훅 프로그램이 실패하면 빌드 루프가 종료됩니다.

구체적으로 말하면, 이 구현을 사용하면 네트워크 연결이 느리거나 불안정할 때 Nix가 느려지거나 사용할 수 없게 됩니다. 더 발전된 구현에서는 스토어 경로를 사용자가 제공한 데몬이나 큐에 넘겨 빌드 루프 밖에서 스토어 경로를 처리하게 할 수 있습니다.

## 사전 준비 사항

이 튜토리얼은 [S3 호환 바이너리 캐시를 설정했고](https://nix.dev/manual/nix/2.22/store/types/s3-binary-cache-store#authenticated-writes-to-your-s3-compatible-binary-cache), `root` 사용자의 기본 AWS 프로필로 버킷에 업로드할 수 있다고 가정합니다.

## 서명 키 설정하기

[`nix-store --generate-binary-cache-key`](https://nix.dev/manual/nix/2.22/command-ref/nix-store/generate-binary-cache-key)를 사용하여 암호화 키 쌍을 생성하십시오. 개인 키로 경로에 서명하고, 경로의 진위를 검증할 수 있도록 공개 키를 배포합니다.

```console
$ nix-store --generate-binary-cache-key example-nix-cache-1 /etc/nix/key.private /etc/nix/key.public
$ cat /etc/nix/key.public
example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
```

버킷에 접근할 모든 머신에서 [](custom-binary-cache). 예를 들어, `nix.conf`의 [`substituters`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-substituters)에 캐시 URL을, [`trusted-public-keys`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-trusted-public-keys)에 공개 키를 추가하십시오:

```
substituters = https://cache.nixos.org/ s3://example-nix-cache
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
```

캐시용으로 빌드하는 머신은 개인 키를 사용하여 derivation에 서명해야 합니다. 방금 생성한 개인 키가 담긴 파일의 경로를 해당 머신의 [`secret-key-files`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-secret-key-files) 설정에 추가해야 합니다:

```
secret-key-files = /etc/nix/key.private
```

## 빌드 훅 구현하기

다음 스크립트를 `/etc/nix/upload-to-cache.sh`에 작성하십시오:

```bash
#!/bin/sh
set -eu
set -f # disable globbing
export IFS=' '
echo "Uploading paths" $OUT_PATHS
exec nix copy --to "s3://example-nix-cache" $OUT_PATHS
```

`$OUT_PATHS` 변수는 공백으로 구분된 Nix 스토어 경로 목록입니다. 여기서는 셸이 단어 분할을 수행하여 각 출력 경로가 `nix store sign`의 개별 인자가 되기를 기대하며, 또 그렇게 되어야 합니다. Nix는 경로에 공백이 포함되지 않음을 보장하지만, 스토어 경로에 glob 문자가 포함될 수는 있습니다. `set -f`는 셸의 glob 확장을 비활성화합니다.

`root` 사용자가 훅 프로그램을 실행할 수 있는지 확인하십시오:

```console
# chmod +x /etc/nix/upload-to-cache.sh
```

## Nix 설정 업데이트하기

로컬 머신에서 훅이 실행되도록 [`post-build-hook`](https://nix.dev/manual/nix/2.22/command-ref/conf-file#conf-post-build-hook) 설정 옵션을 지정하십시오:

```
post-build-hook = /etc/nix/upload-to-cache.sh
```

그런 다음 관련된 모든 머신에서 `nix-daemon`을 재시작하십시오. 예를 들면 다음과 같습니다.

```
pkill nix-daemon
```

## 테스트

아무 derivation이나 빌드하십시오. 예를 들면 다음과 같습니다.

```console
$ nix-build -E '(import <nixpkgs> {}).writeText "example" (builtins.toString builtins.currentTime)'
this derivation will be built:
  /nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv
building '/nix/store/s4pnfbkalzy5qz57qs6yybna8wylkig6-example.drv'...
running post-build-hook '/home/grahamc/projects/github.com/NixOS/nix/post-hook.sh'...
post-build-hook: Signing paths /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
post-build-hook: Uploading paths /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
/nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
```

훅이 적용되었는지 확인하려면 스토어에서 해당 경로를 삭제한 뒤 바이너리 캐시에서 대체해 보십시오:

```console
$ rm ./result
$ nix-store --delete /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
$ nix-store --realise /nix/store/ibcyipq5gf91838ldx40mjsp0b8w9n18-example
copying path '/nix/store/m8bmqwrch6l3h8s0k3d673xpmipcdpsa-example from 's3://example-nix-cache'...
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/nix/store/m8bmqwrch6l3h8s0k3d673xpmipcdpsa-example
```

## 결론

이제 모든 로컬 빌드를 자동으로 서명하여 원격 S3 호환 바이너리 캐시에 업로드하도록 Nix를 설정했습니다.

이를 프로덕션에 배포하기 전에 반드시 [구현상 주의 사항](#implementation-caveats)을 검토하십시오.
