본문으로 건너뛰기

© 2026 Molayo

GeekNews헤드라인2026. 06. 23. 09:36

Nix에는 재배치 가능한 바이너리가 필요함

요약

Nix 패키지 관리자의 고정된 store prefix 문제를 해결하기 위해 재배치 가능한 바이너리 도입을 제안합니다. rootless 환경에서 store 위치를 변경할 때 발생하는 해시 불일치와 재컴파일 문제를 $ORIGIN 기반의 상대 경로를 통해 해결하고자 합니다.

핵심 포인트

  • Nix의 고정된 /nix/store prefix는 rootless 환경에서 제약을 유발함
  • store 경로 변경 시 해시가 달라지면 바이너리 캐시 활용이 불가능해짐
  • ELF RUNPATH에 $ORIGIN 기반 상대 경로를 사용하여 재배치 가능성 확보 제안
  • 커널의 PT_INTERP 및 shebang 지원 미비가 주요 기술적 병목임

store 기반 패키지 관리자 인 Nix는 /nix/store

같은 고정 prefix에 패키지를 두도록 설계되어, 기존 Nix 설치나 root 권한 없이 다른 위치에 store를 두려는 rootless Nix 환경에서 제약이 커짐
--store /tmp/...

chroot

·mount namespace를 함께 쓰면 기존 /nix/store

빌드와 같은 해시를 유지해 cache.nixos.org

같은 바이너리 캐시 를 계속 활용할 수 있음
namespace 없이 local?store=/tmp/...

로 store prefix를 바꾸면 해시가 달라지고, 단순한 hello

빌드도 의존성 그래프 전체 무효화와 GCC 재컴파일로 이어질 수 있음
제안의 핵심은 ELF RUNPATH

에 절대 경로 대신 Linux 동적 링커가 지원하는 $ORIGIN

기반 상대 경로를 써서 store 위치 변경이 해시와 재컴파일로 번지지 않게 하는 것임
실제 재배치 가능성을 막는 병목은 커널이 ELF PT_INTERP

와 스크립트 shebang에서 $ORIGIN

을 지원하지 않는 점이며, 커널 패치·정적 래퍼·언어별 상대 경로·relocatable = true;

메타데이터가 해결 방향으로 제안됨
고정 store prefix와 rootless Nix의 충돌
Nix와 Guix 같은 store 기반 시스템 은 모든 패키지를 정해진 prefix 아래 저장함
Nix는 /nix/store

Guix는 /gnu/store

이 구조에서는 바이너리나 라이브러리 경로를 재작성하기 쉬움
예를 들어 /bin/bash

/nix/store/gik3rh1vz2jlgnifb9dh6vc6sxwwz9jj-bash-5.3p9/bin/bash

같은 전체 store 경로로 바꿀 수 있음
다른 위치에 store를 두고 싶은 상황도 있음
Nix가 이미 설치되어 있지 않은 환경
필요한 권한이 없는 환경
이런 경우가 “rootless Nix” 문제로 이어짐
Nix는 현재도 다른 store 경로를 지정할 수 있지만, 방식에 따라 해시 유지 여부 가 갈림
nix build nixpkgs#hello

/nix/store/zi2bj2hlavv8q743li2s9diqbcpmrf9b-hello-2.12.3/

에 설치함
nix build --store /tmp/fzakaria/store nixpkgs#hello

chroot

와 mount namespace를 사용해 /tmp/fzakaria/store/nix/store/zi2bj2hlavv8q743li2s9diqbcpmrf9b-hello-2.12.3/

에 설치함
두 경우 모두 해시 zi2bj2hlavv8q743li2s9diqbcpmrf9b

가 같음
해시가 같으면 https://cache.nixos.org 같은 바이너리 substituter 의 사전 계산된 derivation을 활용할 수 있음
namespace 없이 store를 바꿀 때의 비용
Bazel 이나 Buck2 같은 도구는 자체 샌드박싱을 위해 namespace를 이미 사용할 가능성이 있음
이런 생태계에 Nix를 통합하려 하면 중첩 user namespace와 mount 제한 때문에 실용성이 크게 떨어짐
chroot

와 mount namespace 없이도 대체 store prefix를 지정할 수는 있지만, 해시가 달라지는 결함이 있음
예시 명령은 --store 'local?store=/tmp/fzakaria/store&state=/tmp/fzakaria/state&log=/tmp/fzakaria/log'

를 사용함
결과 hello

경로는 /tmp/fzakaria/store/qv3fhi1j9gh27fyds5n5b16yia8i6zn5-hello-2.12.3

해시는 기존 zi2...

가 아니라 qv3fhi1j9gh27fyds5n5b16yia8i6zn5

로 바뀜
단순한 store prefix 문자열 변경이 의존성 그래프 전체 를 연쇄 무효화함
다른 폴더에서 “Hello World”를 출력하려는 것만으로 GCC를 4시간 컴파일하게 될 수 있음
이 경우 공개 캐시를 활용할 수 없음
이 한계는 현재 Nix 문서 에도 명시되어 있음
$ORIGIN

이 해결하는 부분과 남는 커널 한계
문제의 원인은 store prefix가 derivation 자체의 일부 라서 해시 계산에 영향을 준다는 점임
전체 store prefix를 모든 곳에 쓰지 않고 상대 경로를 쓰면 해시 변화를 피할 수 있음
ELF 바이너리의 RUNPATH

는 적용 가능한 지점 중 하나임
현재 hello

RUNPATH

예시는 /nix/store/57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib

Linux 로더는 실행 파일이 있는 디렉터리를 뜻하는 $ORIGIN

을 지원함
따라서 RUNPATH

$ORIGIN/../../57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib

처럼 쓸 수 있음
이렇게 하면 store 위치가 바뀌어도 해시가 바뀌지 않고 재컴파일도 필요 없어짐
하지만 동적 링커가 RUNPATH

를 읽기 전에 Linux 커널이 먼저 동적 링커 자체를 로드해야 함
이 경로는 ELF의 PT_INTERP

헤더에 저장됨
예시는 /nix/store/57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib/ld-linux-x86-64.so.2

현재 Linux 커널은 PT_INTERP

에서 $ORIGIN

을 지원하지 않음
스크립트 shebang도 같은 제약을 가짐
예시는 #!/nix/store/gik3rh1vz2jlgnifb9dh6vc6sxwwz9jj-bash-5.3p9/bin/bash

커널은 #!

를 파싱할 때 절대 경로를 기대함
shebang에서도 현재 $ORIGIN

지원이 없음
현재 작업 디렉터리 기준 상대 경로는 사용할 수 있지만, 다른 위치에서 스크립트를 실행하면 깨지므로 신뢰하기 어려움
재배치 가능한 바이너리로 가는 제안
진정한 재배치 가능한 바이너리 를 만들려면 커널 제약을 우회하거나 바꿔야 함
제안된 접근은 세 가지임
Linux 커널을 패치해 PT_INTERP

와 shebang에서 $ORIGIN

을 지원함
모든 바이너리를 작은 정적 바이너리로 감싸고, 래퍼가 자기 위치를 계산한 뒤 동적 링커를 실행함
파일 위치도 언어별 상대 경로 기능을 활용하도록 바꿈
Python에서는 __file__

로 자기 자신 기준 파일 접근을 할 수 있음
가장 적합한 접근으로는 Linux 커널 지원 확장 이 제안됨
NixOS 머신에서는 Nix로 커널을 패치해 해당 지원을 추가할 수 있음
추가로 각 derivation에 재배치 가능 여부를 나타내는 relocatable = true;

메타데이터를 넣는 방안이 제안됨
댓글과 토론

AI 자동 생성 콘텐츠

본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0