Nix로 만드는 프로젝트별 개발 환경
Nix는 기능이 방대한 만큼 학습 곡선도 가파른 도구입니다. 단일 패키지 설치부터 운영체제의 모든 파일과 애플리케이션을 관리하는 일까지 무엇이든 할 수 있습니다.
Nix의 유용한 기능 중 하나는 완전 초보자라도 바로 활용할 수 있는 개발 환경 관리입니다.
Nix를 사용하면 같은 시스템 안에서 여러 프로젝트가 각각 어떤 의존성을 사용할 수 있는지에 대한 독립적인 뷰를 가질 수 있습니다. 예를 들어 Python 2.7과 Node.js 4.x를 사용하는 레거시 프로젝트와 Python 3.11과 Node.js 20을 사용하는 최신 프로젝트를 나란히 두고도 서로 간섭하지 않고 실행할 수 있습니다.
Nix 경험이 전혀 없더라도 20분 정도만 투자하면 Nix로 관리되는 개발 환경을 사용할 수 있습니다.
참고: 저는 아직 Nix 초보자라 제가 하는 방식이 최적의 해법인지 확신할 수 없습니다. 더 경험이 많은 Nix 사용자분들께서 개선 아이디어가 있으시면 알려주시기 바랍니다. 반영하여 글을 업데이트하겠습니다.
왜 Docker로 개발 환경을 관리하지 않나요?
저는 Docker를 좋아하고 배포나 일부 DevOps 작업에 사용하고 있지만, 개발 환경을 관리하는 데에는 그다지 도움이 되지 않았습니다.
저는 VS Code에서 SSH로 연결해 개발하는데, Docker를 쓰면 이 과정이 매우 번거로워집니다. 우회 방법이 있다는 건 알지만 마음에 드는 방식을 찾지 못했습니다.
왜 Ansible로 개발 환경을 관리하지 않나요?
지난 6년간 Ansible로 개발 환경을 관리해 왔습니다. 그런대로 잘 동작했습니다.
제가 진행하는 모든 소프트웨어 프로젝트마다 전용 가상 머신을 만들고, 해당 VM에 필요한 모든 의존성을 구성하는 Ansible 플레이북을 함께 만들었습니다.
문제는 몇 분 정도 간단히 실험해 보고 싶을 때도 VM을 새로 띄우고 플레이북을 작성한 뒤 Ansible이 서버를 프로비저닝할 때까지 10~20분을 기다려야 한다는 점이었습니다. 그 과정이 그다지 내키지 않았습니다.
Nix가 훨씬 가볍기 때문에 모든 프로젝트를 Ansible 대신 Nix를 쓰도록 서서히 옮기고 있습니다. Ansible로 의존성을 하나 업그레이드하는 데 보통 20분 정도 걸리던 작업이 Nix에서는 2분 정도면 됩니다.
간단한 Nix 개발 환경 만들기
Nix 개발 환경이 어떻게 동작하는지 보여드리기 위해 아무것도 설치되지 않은 Debian 11 시스템에서 시작하겠습니다.
Nix 설치하기
먼저 Nix를 설치합니다. 공식 Nix 인스톨러 대신 서드파티인 Determinate Systems 인스톨러를 사용하겠습니다. 이 인스톨러가 여기에서 보여드릴 내용에 유용한 몇 가지 주관적인 설정 결정을 대신해 주기 때문입니다.
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install && . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh간단한 Python 2.7 애플리케이션 만들기
Nix 개발 환경이 실제로 동작하는 모습을 보여드리기 위해 2020년에 공식 지원이 종료된 레거시 버전인 Python 2.7에서 실행되는 간단한 애플리케이션을 만들어 보겠습니다.
먼저 프로젝트용 새 디렉터리를 만듭니다.
mkdir example && cd example다음으로 Nix 개발 환경을 정의하는 파일인 아래 Nix flake를 다운로드하거나 복사합니다:
{
description = "Demo Nix dev environment";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
# 2.7.18.7 release
python-nixpkgs.url = "github:NixOS/nixpkgs/517501bcf14ae6ec47efd6a17dda0ca8e6d866f9";
};
outputs = {
self,
flake-utils,
python-nixpkgs,
} @ inputs:
flake-utils.lib.eachDefaultSystem (system: let
python-nixpkgs = inputs.python-nixpkgs.legacyPackages.${system};
in {
devShells.default = python-nixpkgs.mkShell {
packages = [
python-nixpkgs.python2
];
shellHook = ''
python --version
'';
};
});
}curl --show-error --fail https://mtlynch.io/notes/nixos-dev-environment/flake.nix > flake.nixNix에 익숙하지 않다면 flake.nix 파일이 복잡한 문법으로 가득해 보일 수 있지만, 대부분 단순한 보일러플레이트입니다. 자세한 내용은 아래에서 설명하겠습니다.
이제 Nix 개발 환경을 실행해 볼 차례입니다. 처음 실행할 때는 모든 것을 초기화하는 데 몇 분이 걸리지만, 그 이후에는 몇 초 안에 완료됩니다.
# We need NIXPKGS_ALLOW_INSECURE and --impure because Python 2.7 is past end of
# life.
$ NIXPKGS_ALLOW_INSECURE=1 nix develop --impure
Python 2.7.18.7성공입니다! Python 2.7 환경을 사용할 수 있게 되었습니다.
이 특정 Nix 환경 바깥에는 Python 2.7을 전혀 설치하지 않았다는 점에 유의하세요. nix develop을 실행하지 않고 새 터미널을 열면 Python이 설치되지 않았다는 다음과 같은 오류 메시지가 나타납니다:
$ python --version
-bash: python: command not found다시 Python 2.7 Nix 환경으로 돌아와 Python 3에서는 동작하지 않는, 예전의 악명 높은 print 구문을 사용한 간단한 Python 스크립트를 실행해 보겠습니다:
$ echo 'print "hello, world!"' > main.py && python main.py
hello, world!좋습니다! 이 환경에서 레거시 Python 2.7 코드를 실행할 수 있습니다.
버전 문자열 찾기
그렇다면 제 flake.nix 파일은 어떻게 동작할까요?
flake.nix 파일의 앞부분에서는 원하는 Python 패키지의 정확한 버전을 선언합니다:
{
# 2.7.18.7 release
python-nixpkgs.url = "github:NixOS/nixpkgs/517501bcf14ae6ec47efd6a17dda0ca8e6d866f9";# 2.7.18.7 release 줄은 제가 참고하려고 남긴 주석일 뿐이며 Nix는 이를 무시합니다. 실제로 중요한 역할을 하는 부분은 python-nixpkgs 줄입니다.
NixOS/nixpkgs는 GitHub 저장소이며, 517501bcf14ae6ec47efd6a17dda0ca8e6d866f9는 해당 저장소에서 python2 패키지가 Python 2.7.18.7에 해당하던 버전(커밋)입니다.
그 긴 버전 문자열을 어떻게 알았을까요? Nixhub를 사용했습니다.
Nixhub는 Nix 기반 개발자 도구를 판매하는 회사인 Jetpack이 만든 무료 패키지 검색 서비스입니다.
Nixhub는 불과 세 달 전에 공개되었는데, 덕분에 Nix를 다루는 일이 훨씬 수월해졌습니다. 특정 패키지 버전의 해시를 찾고 싶을 때 Nixhub에서 검색하면 커밋 ID를 찾을 수 있습니다.
그래서 Python 2.7.18.7의 버전 문자열을 찾기 위해 Nixhub에서 python을 검색한 뒤, 결과 목록을 내려 가장 최신의 Python 2.7.x 버전을 찾았습니다:

NixHub를 이용하면 사람이 읽기 쉬운 버전 문자열을 nixpkgs 참조와 패키지 이름으로 변환할 수 있습니다.
솔직히 말해서 정확한 패키지 버전을 고정하는 일은 상당히 번거롭습니다. 언젠가는 원하는 버전의 git 커밋 해시를 찾아 헤매는 이런 우회적인 과정을 거치지 않고도 단순히 2.7.18.7 버전을 원한다고 지정할 수 있을 만큼 Nix 툴링이 발전하기를 바랍니다. 하지만 지금으로서는 제가 아는 한 이것이 버전을 고정하는 가장 좋은 방법입니다.
flake.nix 파일 이해하기
앞서 보여드린 flake.nix 파일에 대해 더 자세히 설명하겠다고 말씀드렸죠.
Nix flake에 대한 모든 것을 설명하지는 않겠습니다. 저 자신도 깊이 이해하고 있지 않기 때문입니다. 여러분이 직접 개발 환경을 만드는 데 필요한 최소한의 내용만 설명하겠습니다. Nix flake에 대해 더 깊이 알고 싶다면 “Practical Nix Flakes.”를 참고하세요.
inputs 섹션은 환경에 포함하려는 다양한 Nix 소스의 버전을 지정하는 곳입니다. 저는 GitHub 저장소용 특수 구문을 사용하고 있지만, 다른 소스 저장소나 URL에서도 가져올 수 있습니다.
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
# 2.7.18.7 release
python-nixpkgs.url = "github:NixOS/nixpkgs/517501bcf14ae6ec47efd6a17dda0ca8e6d866f9";
};devshells.default는 Nix 셸의 개발 환경을 정의합니다. packages에는 환경에서 사용하려는 모든 패키지 목록이 들어갑니다.
{
devShells.default = python-nixpkgs.mkShell {
packages = [
python-nixpkgs.python2
];대부분의 패키지는 이름에 버전이 붙지 않습니다. htop이나 vim 같은 패키지는 이름이 항상 동일하지만, Python처럼 같은 Nixpkgs 버전 안에서도 여러 버전이 제공되는 패키지는 Python 3와 혼동을 피하기 위해 python이 아니라 python2라고 지정해야 합니다.
마지막으로 중요한 부분은 shellHook 섹션입니다.
{
shellHook = ''
python --version
'';Nix는 셸로 진입하기 직전에 shellHook에 있는 명령어를 실행합니다. 이곳에는 어떤 셸 명령어든 넣을 수 있습니다.
저는 Nix flake가 제대로 동작하는지 쉽게 확인할 수 있도록 의존성 버전을 출력하는 명령어를 넣어두는 것을 좋아합니다.
Python 3로 업그레이드하기
이제 한 줄짜리 Python 앱을 Python 2.7에서 최신 Python 3로 포팅하는 수고를 할 준비가 되었다고 가정해 보겠습니다. 다음 두 코드 조각만 업데이트하면 됩니다:
{
# 3.12.0 release
python-nixpkgs.url = "github:NixOS/nixpkgs/e2b8feae8470705c3f331901ae057da3095cea10";{
packages = [
python-nixpkgs.python312
];새로운 Python 3용 flake는 다음과 같이 생겼습니다:
{
description = "Demo Nix dev environment";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
# 3.12.0 release
python-nixpkgs.url = "github:NixOS/nixpkgs/e2b8feae8470705c3f331901ae057da3095cea10";
};
outputs = { self, flake-utils, python-nixpkgs }@inputs :
flake-utils.lib.eachDefaultSystem (system:
let
python-nixpkgs = inputs.python-nixpkgs.legacyPackages.${system};
in
{
devShells.default = python-nixpkgs.mkShell {
packages = [
python-nixpkgs.python312
];
shellHook = ''
python --version
'';
};
});
}Ctrl+D를 누르거나 exit을 입력해 원래 Nix 셸을 종료한 뒤, 다음 명령어로 새로운 Python 3 환경을 초기화합니다:
$ nix develop
warning: updating lock file '/home/mike/example/flake.lock':
• Updated input 'python-nixpkgs':
'github:NixOS/nixpkgs/517501bcf14ae6ec47efd6a17dda0ca8e6d866f9' (2023-09-27)
→ 'github:NixOS/nixpkgs/e2b8feae8470705c3f331901ae057da3095cea10' (2023-10-03)
Python 3.12.0최신 Python 버전은 안전하지 않다고 간주되지 않으므로, Python 2.7에서 필요했던 NIXPKGS_ALLOW_INSECURE 옵션은 편리하게 생략할 수 있습니다.
이제 Python 3 환경에 들어와 있을 겁니다. 이를 확인하기 위해 Python 2 스타일의 main.py를 실행해 보고 Python 3가 제대로 경악하며 오류를 내는지 확인해 보겠습니다:
$ python main.py
File "/home/mike/example/main.py", line 1
print "hello, world!"
^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?Python 3가 의도대로 동작하는 것 같습니다. Python 3 문법에 맞게 수정한 뒤 다시 시도해 보겠습니다:
$ echo 'print("hello, world!")' > main.py && python main.py
hello, world!다시 모든 것이 정상입니다. Nix flake의 몇 줄만 바꿔서 환경을 Python 2.7에서 Python 3.12로 업데이트했습니다!
새로운 의존성 추가하기
패키지를 업데이트하는 방법을 보여드렸는데, 새로운 의존성을 추가하는 것은 어떨까요?
제 Python 파일을 자동으로 실행하는 새로운 bash 스크립트를 추가해 보겠습니다.
(cat <<EOF
#!/usr/bin/env bash
set -eux
readonly MAIN_SCRIPT="main.py"
python $MAIN_SCRIPT
EOF
) > run.sh && chmod +x run.sh && ./run.sh다음과 같은 출력이 나타나야 합니다:
+ readonly MAIN_SCRIPT=main.py
+ MAIN_SCRIPT=main.py
+ python main.py
hello, world!저는 bash에 약하기 때문에 정적 분석 도구가 제 run.sh 스크립트를 개선하는 데 도움이 될 수 있습니다.
shellcheck는 bash 스크립트용 훌륭한 린터이며, 저는 bash 코드를 작성하는 곳이면 어디서든 사용합니다. shellcheck를 개발 환경으로 가져와 잠재적인 bash 함정에 대한 조언을 얻고 싶어서 Nix flake를 다음과 같이 업데이트합니다:
{
description = "Demo Nix dev environment";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
# 3.12.0 release
python-nixpkgs.url = "github:NixOS/nixpkgs/e2b8feae8470705c3f331901ae057da3095cea10";
# 0.9.0 release
shellcheck-nixpkgs.url = "github:NixOS/nixpkgs/8b5ab8341e33322e5b66fb46ce23d724050f6606";
};
outputs = { self, flake-utils, python-nixpkgs, shellcheck-nixpkgs }@inputs :
flake-utils.lib.eachDefaultSystem (system:
let
python-nixpkgs = inputs.python-nixpkgs.legacyPackages.${system};
shellcheck-nixpkgs = inputs.shellcheck-nixpkgs.legacyPackages.${system};
in
{
devShells.default = python-nixpkgs.mkShell {
packages = [
python-nixpkgs.python312
shellcheck-nixpkgs.shellcheck
];
shellHook = ''
python --version
echo "shellcheck" "$(shellcheck --version | grep '^version:')"
'';
};
});
}다시 Ctrl+D를 누르거나 exit을 입력해 원래 Nix 셸을 종료하고 다음 명령어로 새 셸을 생성합니다:
$ nix develop
warning: updating lock file '/home/mike/example/flake.lock':
• Added input 'shellcheck-nixpkgs':
'github:NixOS/nixpkgs/8b5ab8341e33322e5b66fb46ce23d724050f6606' (2023-09-19)
Python 3.12.0
shellcheck version: 0.9.0모든 것이 잘 되고 있습니다. shellcheck가 제가 요청한 버전인 0.9.0을 보고합니다.
이제 run.sh 스크립트에 대해 shellcheck를 실행해 볼 차례입니다.
$ shellcheck -o all run.sh
In run.sh line 6:
python $MAIN_SCRIPT
^----------^ SC2248 (style): Prefer double quoting even when variables don't contain special characters.
^----------^ SC2250 (style): Prefer putting braces around variable references even when not strictly required.
Did you mean:
python "${MAIN_SCRIPT}"
For more information:
https://www.shellcheck.net/wiki/SC2248 -- Prefer double quoting even when v...
https://www.shellcheck.net/wiki/SC2250 -- Prefer putting braces around vari...오, 동작합니다!
사소해 보이지만, 이는 제가 과거에 겪었던 큰 문제를 해결해 줍니다. 저는 모든 프로젝트에서 shellcheck를 git pre-commit 훅으로 실행하는 것을 좋아하지만, 지금까지는 항상 시스템 전체에 설치된 단일 버전의 shellcheck에 의존해야 했습니다. 만약 shellcheck의 새로운 규칙을 특정 프로젝트에 적용하고 싶으면, pre-commit 훅이 모든 프로젝트에서 실패하기 시작할 수도 있었습니다.
Nix를 사용하면 각 프로젝트를 원하는 린터 버전에 바인딩할 수 있습니다. 즉, 전역에서 단일 버전을 공유하는 대신 프로젝트별로 린터를 업그레이드할 수 있습니다.
direnv로 Nix 개발 셸 자동 로드하기
Nix 개발 셸은 잘 동작하지만, 새 터미널 창을 열 때마다 nix develop을 입력해 셸에 진입해야 한다는 의미입니다.
이를 자동화할 수 있을까요? direnv를 사용하면 가능하다는 것을 알게 되었습니다.
direnv는 프로젝트 디렉터리로 cd할 때마다 Nix 셸을 자동으로 로드하고, 디렉터리에서 빠져나오면 자동으로 언로드합니다.
direnv는 일반 apt 패키지로 제공되지만, 짜증스럽게도 Debian Bullseye 및 그 이전 버전에서는 사용 가능한 최신 패키지가 2.25.0입니다.
Nix flake를 사용하고 있으므로 2.29.0 이상의 direnv가 필요해서, 대신 공식 direnv 인스톨러를 사용하겠습니다:
curl -sfL https://direnv.net/install.sh | sudo bin_path=/usr/local/bin bash && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && . ~/.bashrcdirenv를 --version 플래그와 함께 실행하면 최신 버전을 사용하고 있음을 확인할 수 있습니다:
$ direnv --version
2.32.3프로젝트에서 direnv를 활성화하려면 Nix flake가 있는 디렉터리로 이동해 다음 명령어를 실행해야 합니다:
echo 'use flake .' > .envrc && direnv allow이제 프로젝트 디렉터리로 cd할 때마다 direnv가 Nix 환경을 자동으로 로드하고, 디렉터리에서 나가면 언로드합니다.
직접 소유하지 않은 프로젝트를 위한 개발 셸 만들기
저처럼 개발 셸을 좋아하게 되면 작업하는 모든 프로젝트에서 사용하고 싶어질 것입니다.
다른 사람의 저장소에서 작업하는데 상대방이 전혀 Nix를 도입하고 싶어 하지 않을 때는 어떻게 해야 할까요?
이 상황을 처리하는 가장 쉬운 방법은 Nix flake 전용 디렉터리를 만들고, 그 안에 서드파티 저장소를 폴더로 넣는 것입니다. 예를 들면 다음과 같습니다:
.
├── examplerepo/ << The actual git repo
├── flake.lock
└── flake.nix이에 대해서는 “Use a Nix Flake without Adding it to Git”에서 더 자세히 설명합니다.
의존성이 늘어날수록 초기화는 느려집니다
제가 발견한 Nix 개발 환경의 가장 큰 단점은 환경 로드 시간이 느리다는 점입니다. 보통 디렉터리로 cd하는 것은 밀리초 단위로 이루어지지만, Nix 환경을 로드해야 하면 5~10초가 걸릴 수 있습니다.
더 큰 문제는 의존성이 많아질수록 로드 시간이 더 느려진다는 것입니다. Nix는 각 의존성마다 별도의 nixpkgs 인스턴스를 유지해야 하므로, 사용하려는 개발 도구가 하나 늘어날 때마다 디렉터리 로드 시간이라는 대가를 치러야 합니다.
안타깝게도 이 문제에 대한 해결책을 찾지 못했습니다.
CI에서 Nix를 위한 좋은 해결책이 없습니다
프로젝트를 위해 독립적이고 재현 가능한 개발 환경을 만들기 위해 이렇게 많은 노력을 기울인 만큼, 당연히 지속적 통합(CI)에서 코드를 실행할 때도 이 환경을 재사용하고 싶습니다. 안타깝게도 CI 워크플로에 Nix를 통합하는 실용적인 방법을 찾지 못했습니다.
CI에서 Nix의 문제는 Nix가 자체 환경을 만드는 데 초기에 많은 작업을 해야 한다는 점입니다. 제 로컬 개발 시스템에서는 Nix가 처음으로 환경을 초기화하는 데 60~180초가 걸리며, 보통 패키지 서버에서 수 기가바이트의 데이터를 다운로드합니다.
느린 초기화는 로컬 시스템에서는 한 번만 수행하면 되므로 짜증나지만 감수할 만합니다. 하지만 CI에서는 더 큰 문제입니다. 기존에 10초면 끝나던 간단한 CI 단계가 Nix 초기화에 2분, 그리고 제가 실제로 원하는 작업에 10초가 걸리며 부풀어 오르기 때문입니다.
Nix 전용 클라우드 캐시인 Cachix를 사용해 보기도 했습니다. 어느 정도 도움이 된 것 같기도 하지만, CI 단계당 초기 로드 시간을 90초 이하로 줄이는 방법은 찾지 못했습니다.
Nix를 중심으로 구축된 몇 가지 CI 솔루션(Garnix, Hercules, smithy)이 있지만, 아직 시도해 보지는 않았습니다. 완전히 새로운 CI 시스템을 배워야 하는 대신, 이미 잘 알고 있는 CircleCI 환경에서 Nix를 사용하고 싶습니다.
제가 꿈꾸는 기능: Nix가 언어별 의존성을 관리해 주는 것
Nix가 할 수 있을 것 같지만 방법을 찾지 못한 것 중 하나가 언어별 의존성을 관리하는 일입니다.
예를 들어 Nix로 requirements.txt 파일에 pip 의존성 목록이 있는 Python 3 프로젝트를 만들 때, Nix가 “어, requirements.txt가 바뀌었네! 환경도 맞춰서 업데이트할게”라고 말해주면 좋겠습니다. Node.js와 package.json 파일도 마찬가지입니다. 하지만 지금까지는 Nix가 그런 파일을 감시하도록 만들 방법을 찾지 못했습니다.
poetry2nix를 본 적은 있지만, 제 Python 프로젝트에서 Poetry를 사용하지 않기 때문에 시도해 보지는 않았습니다. 하지만 제가 상상하는 기능을 구현하는 방법을 아시는 독자분이 계시다면 댓글로 알려주시기 바랍니다.
업데이트 (2023-10-28): pyproject.nix가 일반 requirements.txt 파일을 지원한다는 것을 알게 되었습니다. 그래서 현재는 그 방식을 사용하고 있습니다.
업데이트 (2025-01-17): pyproject.nix가 너무 혼란스러워 사용을 중단했습니다. Nix 메인테이너가 직접 Nix로 포팅한 PyPI 패키지에서만 동작하는 것 같고, 그 외의 패키지에서는 혼란스러운 방식으로 실패합니다.
주의할 점
모든 Nix 모험이 그렇듯, Nix 개발 환경에도 수많은 함정이 있습니다. 지금까지 제가 겪은 것들을 아래에 정리했습니다.
Nix는 flake.nix가 git에 있어야 합니다
Nix flake의 이상한 특성 중 하나는 flake가 git으로 관리되는 디렉터리에 있는데 flake.nix 파일을 저장소에 git add하지 않은 경우, 다음과 같은 혼란스러운 오류가 나타난다는 점입니다:
error: getting status of '/nix/store/66snibk6a9y3dbam1ww7fj0bdrh0ylw6-source/flake.nix': No such file or directory이런 경우가 발생하면 git add flake.nix로 해결할 수 있습니다. 변경 사항을 커밋할 필요도 없습니다. flake를 add하는 것만으로 충분합니다.
Go: libc 링크 실패
CGO에 의존하는 제 Go 프로젝트에서 Nix 개발 환경으로 코드를 컴파일하려고 할 때 다음과 같은 오류를 겪었습니다:
runtime.gcdata: missing Go type information for global symbol .dynsym: size 72
runtime/cgo(.text): relocation target stderr not defined
runtime/cgo(.text): relocation target fwrite not defined
runtime/cgo(.text): relocation target vfprintf not definedGo가 바이너리를 libc에 링크하는 데 실패하는 것으로 보입니다. Zig 사용자에게 영향을 미치는 이 이슈와 유사합니다.
Nix 환경의 패키지 목록에 libc와 musl을 추가해 보았지만 아무 효과가 없었습니다.
링킹 문제를 해결한 유일한 방법은 Go 앱을 -tags=netgo,osusergo 옵션으로 컴파일하는 것이었습니다. 왜 그렇게 하면 되는지 전혀 모르겠습니다.
Nix 환경에서 멀티플랫폼 Go 바이너리를 빌드하는 완전한 예시는 제 PicoShare flake와 빌드 스크립트를 참고하세요.
Golang: version X does not match go tool version Y
일부 시스템에서 빌드 스크립트를 실행할 때 다음과 같은 오류가 발생하기 시작했습니다:
compile: version "go1.18.4" does not match go tool version "go1.19.6"알고 보니 제 GOROOT 환경 변수가 Nix 환경 바깥에 있는 Go 컴파일러 버전을 가리키고 있었습니다.
간단한 해결 방법은 다음 명령어를 실행하는 것이었습니다:
unset GOROOT근본적인 해결 방법은 시스템에서 환경 변수를 설정하는 모든 파일을 찾아 GOROOT을 설정하는 파일을 찾는 것이었습니다. GOROOT에 값을 할당하는 줄을 삭제한 뒤에는 시스템을 재부팅해야 했습니다. 새 셸을 시작하는 것만으로는 충분하지 않았습니다.
오래된 패키지 버전은 동작하지 않습니다
특정 패키지의 오래된 버전을 시도해 보았는데, 아예 동작하지 않았습니다.
예를 들어 python39에 대해 nixpkgs 버전 b4e193a23a1c5d8794794e65cabf1f1135d07fd9를 선택하면 Python뿐만 아니라 shellcheck도 깨집니다:
• Updated input 'python-nixpkgs':
'github:NixOS/nixpkgs/e2b8feae8470705c3f331901ae057da3095cea10' (2023-10-03)
→ 'github:NixOS/nixpkgs/b4e193a23a1c5d8794794e65cabf1f1135d07fd9' (2021-02-19)
environment:2863: python: command not found
environment:2864: shellcheck: command not found제 추측으로는 그 정도로 오래된 nixpkgs 버전은 아직 공식적으로 지원되지 않는 Nix의 새로운 기능인 Nix flakes와의 호환성이 확보되기 이전 버전이기 때문인 것 같습니다.
제가 만든 Nix 개발 flake 몇 가지
지금까지 제가 만든 Nix 개발 flake 중 몇 가지를 소개합니다:
- PicoShare - Go 웹 앱
- mtlynch.io - Node.js 의존성이 있는 Hugo 기반 블로그
- python3_seed -
requirements.txt의존성이 있는 기본 Python 앱
참고 자료
Nix 개발 환경을 동작시키는 방법을 알아내는 데 어려움을 겪었습니다. 문서화된 예제를 많이 찾을 수 없었기 때문입니다.
마침내 Nix 환경에 대한 이해가 잡히게 된 계기는 Attila Gulyas의 상세 가이드였습니다.
글을 무작위로 읽기
