Nix 플레이크
Nix 코드를 참조하고 공유하기 위한 시스템
먼저 Nix 빠른 시작부터 따라가고, 개념 문서는 주로 보충 설명이 필요할 때 참고하기를 권합니다. 오른쪽의x를 누르면 모든 개념 문서에서 이 안내를 숨길 수 있습니다.
업스트림 Nix 프로젝트에서 플레이크는 여전히 실험적 기능으로 간주되며, 현재로서는 안정 기능으로 선언할 구체적인 일정이 없습니다. 이 때문에 업스트림 Nix를 사용한다면 플레이크를 명시적으로 활성화해야만 사용할 수 있습니다.
빠른 시작의 첫 부분에서 설치하는
업스트림 Nix와 Determinate Nix 중 무엇을 선택하든, 이미 Nix 사용자라면 플레이크 사용법을 익히고, 이제 막 시작하는 단계라면 플레이크로 Nix 여정을 시작하실 것을 강력히 권장합니다.
Nix 플레이크는 루트에 flake.nix와 flake.lock이 있는 디렉터리로, 다른 사람들이 패키지 빌드, 프로그램 실행, 개발 환경 사용, NixOS 시스템 구축 등에 활용할 수 있는 Nix 표현식을 출력합니다. 필요한 경우 플레이크는 다른 플레이크의 출력을 입력으로 사용할 수 있습니다.
플레이크를 Nix 코드의 처리기로 생각하면 이해하는 데 도움이 될 수 있습니다. 플레이크는 Nix 표현식을 입력으로 받아 패키지 정의, 개발 환경, NixOS 설정처럼 Nix가 사용할 수 있는 것을 출력합니다.
따라서 플레이크는 일종의 사슬을 형성합니다. 예를 들어, 제가 Nixpkgs—이것 역시 플레이크입니다!—가 출력하는 헬퍼 함수를 사용해 패키지 빌드를 정의하는 플레이크를 만든다고 가정해 봅시다. 그러면 제 팀원은 제 플레이크의 패키지 정의를 Nix 개발 환경의 일부로 사용할 수 있습니다. 그다음 다른 팀은 그 개발 환경을 자신들의 프로젝트 중 하나에서 사용할 수 있습니다. 이런 식으로 계속 이어집니다.
플레이크 참조
플레이크 참조는 플레이크가 위치한 곳을 나타내는 문자열 표현입니다. 플레이크 참조는 다음 두 곳에서 사용됩니다.
- 플레이크의 출력에 의존하기 위한 플레이크 입력 선언에서 사용됩니다.
- 셸 환경에서
nix run github:DeterminateSystems/flake-checker와 같은 명령을 실행할 때 플레이크 참조를 사용합니다(이 명령은 flake-checker 프로그램을 실행합니다).
다음은 플레이크 참조의 몇 가지 예시입니다.
| 참조 | 설명 |
|---|---|
path:/home/nix-stuff/my-flake | 현재 호스트의 /home/nix-stuff/my-flake 디렉터리 |
github:DeterminateSystems/zero-to-nix | DeterminateSystems/zero-to-nix GitHub 저장소 |
github:DeterminateSystems/zero-to-nix/other | DeterminateSystems/zero-to-nix GitHub 저장소의 other 브랜치 |
github:DeterminateSystems/zero-to-nix/d51c83a5d206e882a6f15a282e32b7079f5b6d76 | DeterminateSystems/zero-to-nix GitHub 저장소의 커밋 d51c83a5d206e882a6f15a282e32b7079f5b6d76 |
github:DeterminateSystems/zero-to-nix/pull/2/head | DeterminateSystems/zero-to-nix GitHub 저장소의 풀 리퀘스트 1 |
nixpkgs | Nixpkgs의 nixpkgs-unstable 브랜치의 최신 리비전(github:NixOS/nixpkgs의 별칭) |
nixpkgs/release-22.11 | Nixpkgs의 release-22.11 브랜치 |
https://flakehub.com/f/NixOS/nixpkgs/0.2405.* | nixos-24.05 브랜치의 최신 리비전 |
플레이크 참조에 대한 더 체계적인 설명은 공식 문서에서 확인할 수 있습니다.
참조와 리비전
플레이크 참조는 항상 플레이크의 특정 리비전을 가리킵니다. 예를 들어 Nixpkgs는 하나의 플레이크이지만, 수천 개에 이르는 Nixpkgs의 각 리비전마다 플레이크 참조가 있습니다.
플레이크 입력
플레이크 입력은 플레이크를 빌드하는 데 필요한 Nix 의존성입니다. 집합의 각 입력은 GitHub, 일반 Git 저장소, 심지어 여러분의 파일 시스템 등 다양한 소스에서 가져올 수 있습니다.
또한 입력은 서로의 입력을 수정할 수 있으므로, 예를 들어 여러 의존성이 모두 같은 버전의 nixpkgs에 의존하도록 보장할 수 있습니다. 이는 inputs.<input>.follows 속성을 통해 이루어집니다.
{ inputs.nixpkgs.url = "github:NixOS/nixpkgs";}플레이크 입력 스키마에 대한 전체 설명은 Nix 매뉴얼에서 확인할 수 있습니다.
flake.lock 파일
모든 플레이크 입력은 flake.lock이라는 잠금 파일에서 특정 리비전으로 고정됩니다. 이 파일은 리비전 정보를 JSON 형식으로 저장합니다.
flake.lock 파일은 Nix 플레이크가 순수하게 결정론적인 출력을 갖도록 보장합니다. flake.lock 없이 flake.nix 파일만 있다면 불완전한 것, 즉 일종의 원형 플레이크(proto-flake)로 간주해야 합니다. nix build, nix develop, 심지어 nix flake show처럼 플레이크를 대상으로 실행하는 모든 Nix CLI 명령은 flake.lock을 자동으로 생성합니다.
다음은 Nixpkgs를 특정 리비전으로 고정하는 flake.lock 파일의 예시 부분입니다:
{ "nodes": { "nixpkgs": { "locked": { "lastModified": 1668703332, // A SHA of the contents of the flake "narHash": "sha256-PW3vz3ODXaInogvp2IQyDG9lnwmGlf07A6OEeA1Q7sM=", // The GitHub org "owner": "NixOS", // The GitHub repo "repo": "nixpkgs", // The specific revision "rev": "de60d387a0e5737375ee61848872b1c8353f945e", // The type of input "type": "github" } } // Other inputs }}이 flake.lock이 다음과 같은 입력 블록을 가진 flake.nix와 함께 있다면…
{ inputs.nixpkgs.url = "nixpkgs";
outputs = { self, nixpkgs }: { # Define outputs here };}…nixpkgs 속성은 암묵적으로 de60d387a0e5737375ee61848872b1c8353f945e 리비전에 고정됩니다. 해당 리비전 정보가 Nix 코드 자체에는 없더라도 마찬가지입니다.
플레이크 레지스트리
플레이크 레지스트리는 전체 플레이크 참조 대신 기호 식별자를 사용하여 플레이크를 참조할 수 있게 해 주는 편의 기능입니다. 가장 널리 사용되는 기호 식별자는 nixpkgs이며, 이는 github:NixOS/nixpkgs/nixpkgs-unstable 플레이크 참조의 별칭입니다
여러분이 접할 수 있는 몇 가지 기호 식별자는 다음과 같습니다:
| 기호 식별자 | 전체 플레이크 참조 |
|---|---|
nixpkgs | github:NixOS/nixpkgs/nixpkgs-unstable |
flake-utils | github:numtide/flake-utils |
home-manager | github:nix-community/home-manager |
기본 전역 플레이크 레지스트리 전체는 JSON 파일로 관리됩니다.
다음은 기호 식별자를 사용하는 플레이크의 예시입니다:
{ outputs = { self, nixpkgs, flake-utils }: let pkgs = import nixpkgs { inherit system; }; in flake-utils.lib.eachDefaultSystem (system: { devShells.default = pkgs.mkShell { packages = with pkgs; [ curl git jq wget ]; }; });}이 플레이크에서는 inputs 블록이 생략되었다는 점에 유의하십시오. 플레이크 레지스트리 사용은 언제나 선택 사항입니다.
플레이크 출력
플레이크 출력은 플레이크가 빌드 과정에서 만들어 내는 결과물입니다. 각 플레이크는 여러 종류의 출력을 동시에 가질 수 있으며, 그 예는 다음과 같습니다(이에 국한되지 않습니다):
플레이크 출력은 함수로 정의되며, 이 함수는 해당 플레이크의 각 입력(입력 섹션에서 정한 식별자를 이름으로 사용)을 담은 속성 집합을 입력으로 받습니다.
함수 내보내기
플레이크는 패키지나 NixOS 설정 같은 것 외에도 다른 곳에서 사용할 Nix 함수를 출력할 수도 있습니다. 예를 들어 Nixpkgs는 lib 속성을 통해 많은 헬퍼 함수를 출력합니다.
lib 관례lib를 사용해 함수를 출력하는 관례는 Nixpkgs뿐 아니라 다른 많은 Nix 프로젝트에서도 따르고 있습니다. 하지만 원하는 어떤 속성을 통해서든 자유롭게 함수를 출력할 수 있습니다.
다음은 lib 속성을 통해 sayHello 함수를 출력하는 플레이크 예시입니다. 이 함수는 이름을 입력으로 받아 그 이름을 가진 사람에게 인사하는 문자열을 출력합니다:
{ outputs = { self }: { lib = { sayHello = name: "Hello there, ${name}!"; }; };}그러면 다른 Nix 플레이크가 이 플레이크를 입력으로 지정하고 sayHello를 어떤 목적으로든 사용할 수 있습니다.
시스템 특정성
패키지, 개발 환경, NixOS 설정을 비롯한 일부 플레이크 출력은 시스템별로 지정되어야 합니다. 다음은 x86_64-linux 시스템(64비트 AMD/Intel Linux)에서 사용할 수 있는 패키지를 출력하는 플레이크 예시입니다:
{ outputs = { self, nixpkgs }: let # Declare the system system = "x86_64-linux"; # Use a system-specific version of Nixpkgs pkgs = import nixpkgs { inherit system; }; in { # Output `ponysay` as the default package of the flake packages.${system}.default = pkgs.ponysay; };}하지만 많은 경우 패키지나 개발 환경 같은 것을 여러 시스템용으로 출력해야 합니다. flake-utils 같은 헬퍼 라이브러리는 이를 위한 편리한 방법을 제공합니다. 다음과 같이 Nix 함수를 사용할 수도 있습니다:
{ outputs = { self, nixpkgs }: let # The set of systems to provide outputs for allSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
# A function that provides a system-specific Nixpkgs for the desired systems forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { pkgs = import nixpkgs { inherit system; }; }); in { packages = forAllSystems ({ pkgs }: { default = { # Package definition }; }); };}플레이크 템플릿
플레이크 템플릿을 사용하면 미리 제공된 내용으로 새 Nix 프로젝트를 초기화하거나 기존 프로젝트에 파일 묶음을 추가할 수 있습니다. nix flake init 명령으로 플레이크 템플릿을 초기화할 수 있습니다. 플레이크는 templates 속성을 사용하여 템플릿을 출력할 수 있습니다. 다음은 예시입니다:
{ outputs = { self }: { templates = { starter-template = { path = ./my-starter-template; description = "A getting started template for a new Nix project"; }; }; };}이 템플릿 정의에 대해 nix flake init --template <reference>를 실행하면 Nix는 ./my-starter-template 디렉터리의 내용을 현재 디렉터리로 복사합니다(기존 파일은 덮어쓰지 않습니다).