NixOS は Nix パッケージマネージャの上に作られた Linux ディストリビューションである。 システム構成を独自言語 (Nix 言語) で宣言的に記述でき、信頼性のあるアップデードを実現する。
NixOS はカーネルからアプリケーション, システムパッケージ, 設定ファイルに至るまで、OS を構成するすべてをパッケージとして扱い、それらを Nix パッケージマネージャで管理する。
NixOS のシステム構成は Nix 言語で記述された 1 つの構成ファイルによって記述できる。 例として、SSH デーモンをサービスとして起動するシステムの最小構成を下記に示す。
{
boot.loader.grub.device = "/dev/sda";
fileSystems."/".device = "/dev/sda1";
services.sshd.enable = true;
}
構成ファイルを変更した後に、下記のコマンドを実行することによってシステム構成をアップデートできる。
nixos-rebuild switch
アップデートを実行すると、新規に宣言されたシステム構成の反映に要するあらゆる作業 (ex. パッケージソースのダウンロード, パッケージのビルド, 設定ファイルの生成) を行う。
Nix 言語で記述した構成ファイルは純関数型かつ宣言的であることから、同じ構成ファイルからのアップデートは常に同じ結果となる。
NixOS はシステム構成の管理にトランザクションのようなアプローチを導入している。 システム構成のアップデート中に電源が落ちたとしても、システムは整合性のとれた状態に保たれる。
NixOS はアップデートの結果が意図しないものであっても、それをロールバックができる。 ブートメニューにシステム構成のバージョンが表示され、新しいシステム構成がうまく動かないときは古いバージョンを選んで起動できる。
具体的には、下記のコマンドを実行することによってシステムをロールバックできる。
nixos-rebuild switch --rollback
NixOS の宣言的なシステム構成は、他のマシンに同じ構成を再現することを容易にする。 構成ファイルをコピーしてアップデートを実行するだけで、全く同じシステム構成が再現できる。 ただし、 Nix パッケージマネージャで管理されないファイル (ex. ユーザーデータ) は再現されない。
Nix パッケージマネージャでは、Nix 言語を用いてソースコードからパッケージをビルドする方法を記述する。 毎回パッケージをソースコードからビルドするのは時間がかかるので、Nix パッケージマネージャはキャッシュサーバに利用可能な pre-built バイナリがある場合それを利用する。 これによりソースコードベースの柔軟性とバイナリベースの効率性を両立している。
NixOS ではシステム全体で共有されるプロファイルに加えて、各ユーザが自由にパッケージをインストールできる個別のプロファイルが存在する。 よって、ユーザがパッケージをインストールするのに特権を必要としない。
2 つのユーザが同じパッケージの同じバージョンをインストールしても、パッケージのダウンロードやビルドは 1 回のみ行われ、各ユーザは 1 つのパッケージの実体を共有することになる。 Nix パッケージマネージャはこれが安全であることを保証する。
また、Nix パッケージマネージャは同じパッケージの異なるバージョンが共存させることもできる。
ビルドされたパッケージは、パッケージソースやビルド依存などから計算したハッシュによって識別され、読み込み専用の Nix ストア (/nix/store
) に保存される。
パッケージビルドの一部 (ex. ソースコードのバージョン, ビルド依存, コンパイラフラグ含むビルドコマンド) が変更されるとハッシュが変更され、ストア内では全く別のパッケージとして扱われる。
一貫した環境を構築するために、Nix パッケージマネージャは Nix ストアにあるパッケージの symlink をまとめて、プロファイルを /var/nix/profile
以下に作成する。
プロファイルは最終的に ~/.nix-profile
に symlink され、環境変数 (ex. PATH
, MANPATH
, LD_LIBRARY_PATH
) にそれを参照させることで環境が完成する。
古い環境のプロファイルはそのまま保持されるため、環境をロールバックするには、単純に古いプロファイルを symlink しなおせばよい。
この仕様からも分かるように、NixOS は Linux などの Unix 系 OS が本来従うべきファイルシステム改装基準である FHS (= Filesystem Hierarchy Standard) には従わない。
サンドボックスが有効化されている場合、Nix は各ビルドプロセスのために隔離された環境を用意する。 これはビルドの再現性を向上させることに大いに役に立つ。
Nix 式は必要時に評価される。
例えば、下記の Nix 式において abort
は使われていないため、呼ばれることはない。
let
a = abort "will never happen";
b = "hello";
c = "world";
in b + c
Nix 言語は宣言的プログラミングの 1 つである関数型プログラミングのスタイルを採用している。 すべての計算は数学的な純関数の評価によって行われる。 純関数は入力によってのみ出力が決定され、ステートの変更や値の再代入などの副作用を許可しない。