❄️

NixOS と Nix Flakes の紹介

2022/12/17に公開

この記事は「慶應義塾大学 SFC 村井研 (RG) Advent Calendar 2022」の 15 日目の記事です.

概要

この記事では,Linux ディストリビューションである NixOS と,その関連ツールである Nix Flakes について紹介します.

NixOS とは,純粋関数型言語である Nix 言語 で設定を記述したり, Nix パッケージマネージャ を使ってパッケージ管理を行える Linux ディストリビューションです.
Nix Flakes とは, Nix パッケージマネージャで今後主流となっていく,パッケージ・プロジェクト管理機能です.

この記事では,各ソフトウェアの詳細な使い方は説明しません.
雰囲気を紹介して,興味を持っていただくことを目的としています.
実際に使い始めてみる方は,公式マニュアルや有志の Web サイトを参照してみてください.

以下, NixOS と Nix Flakes それぞれについて紹介します.

NixOS

NixOS とは, Linux ディストリビューションです.

システムの設定を純粋関数型言語 Nix で記述することにより,システム環境の再現性を高められることが特徴です.
この宣言的なシステム設定はバージョン管理され,過去の設定に戻りたい時も簡単にロールバックすることができます.

また, NixOS には Nix パッケージマネージャが標準で付属しています. Nix パッケージマネージャも,パッケージのビルド方法を Nix 言語で記述でき,パッケージの再現性と信頼性が高くなっています.

NixOS のインストール

GUI でインストールする方法と,手動でインストールする方法の二つがあります.

ここでは詳しく紹介しませんが, NixOS に興味を持ってくださった方は上記マニュアルを読んでインストールしてみてください.

NixOS のシステム設定

NixOS では, /etc/nixos/configuration.nix にシステム設定を記述します.

以下がサンプルの configuration.nix です.  
Nix 言語について説明していませんが,雰囲気で読んでください.

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:

{
  imports =
    [ # インストール時に生成されたハードウェア設定
      ./hardware-configuration.nix
    ];

  # ブートローダの設定
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;
  boot.loader.efi.efiSysMountPoint = "/boot/efi";

  # 使用する NixOS のバージョン
  system.stateVersion = "22.05";

  # タイムゾーン
  time.timeZone = "Asia/Tokyo";

  # ロケール等の設定
  i18n.defaultLocale = "en_US.utf8";
  i18n.extraLocaleSettings = {
    LC_ADDRESS = "ja_JP.utf8";
    LC_IDENTIFICATION = "ja_JP.utf8";
    LC_MEASUREMENT = "ja_JP.utf8";
    LC_MONETARY = "ja_JP.utf8";
    LC_NAME = "ja_JP.utf8";
    LC_NUMERIC = "ja_JP.utf8";
    LC_PAPER = "ja_JP.utf8";
    LC_TELEPHONE = "ja_JP.utf8";
    LC_TIME = "ja_JP.utf8";
  };

  # キーマップの設定
  console.keyMap = "dvorak";

  # Nix パッケージマネージャで非フリーソフトウェアのインストールを有効化する
  # e.g.) Google Chrome など
  nixpkgs.config.allowUnfree = true;

  # システム全体向けにインストールするパッケージ
  environment.systemPackages = with pkgs; [
    docker
    docker-compose
    gnupg
    python3
    zsh
  ];

  # ユーザに zsh の使用を許可する
  programs.zsh.enable = true;

  # SSH サーバを有効化し,設定する
  services.openssh.enable = true;
  services.openssh.permitRootLogin = "no";
  services.openssh.passwordAuthentication = false;

  # Docker を有効化する
  virtualisation.docker.enable = true;

  # ユーザアカウントの追加
  users.users.kino-ma = {
    isNormalUser = true;
    description = "Seiki Makino";
    extraGroups = [ "networkmanager" "wheel" "docker" ];
    # このユーザだけ利用可能なパッケージ
    packages = with pkgs; [
      htop
    ];

    # ログインシェル
    shell = pkgs.zsh;

    # SSH 公開鍵の登録
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 ..."
    ];
  };
}

コメントを見ていただければ分かる通り,さまざまなシステム設定を宣言的に行うことができます.

  • 使用するキーマップ
  • インストールするパッケージ
  • SSH サーバの有効化
  • Docker の有効化
  • ユーザアカウント
    • 所属するグループ
    • ログインシェル
    • SSH 公開鍵

これ以外にも,非常にたくさんの設定を行うことができます.興味のある方や実際にセットアップを始めた方は,ぜひ マニュアル を参照してみてください [1]

configuration.nix の設定は, nixos-rebuild switch とコマンドを打つことでシステムに反映されます.

この configuration.nix をコピーすることで,別のホストでも全く同じ環境を再現できます.
また,過去の設定にも簡単にロールバックすることができます.
この強みから,普段使いの OS としてはもちろん,サーバ用途としても活躍しやすいのではないかと思います.

簡単ですが、以上が Nix OS の紹介となります。雰囲気や嬉しさが伝わると嬉しいです。

Nix Flakes

次に, Nix 言語 で設定を記述するプロジェクト管理ツール Nix Flakes [2] の紹介をします.
この章の内容は,一部 NixOS Wiki にも書いてあります.

Nix Flakes は, Nix パッケージマネージャの一つの機能です.
Nix パッケージマネージャは NixOS にデフォルトで付属しているほか, macOS や Windows にも インストールすることができます

Nix Flakes は,ソフトウェアのビルド,依存ツールの管理,開発者間での環境の統一,スクリプトの実行など,さまざまな機能を持っています.  
これは,以下のようなさまざまなツールの機能をひとまとめにしたものだと捉えることができます.

  • Make
  • Docker
  • pip, NPM などの各種パッケージマネージャ
  • nodenv などの言語バージョン管理ツール

Nix Flakes によって管理されているプロジェクトのことを, Flake と呼びます.
自分のプロジェクトを Flake として管理したり,他人の Flake をインストールしたりすることができます.
また, configuration.nix の代わりに Flake を記述し,システムの設定を行うこともできます.
dotfiles の代替として使用している人もいるようです.

Nix Flakes の有効化

Nix Flakes はまだ実験段階で,デフォルトでは使用できません.
以下のコマンドを打つことにより,実行したユーザに対して有効化できます.

mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf

または, NixOS 上では configuration.nix に以下の設定を追加すると使用できます.

{ pkgs, ... }: {
  nix.settings.experimental-features = [ "nix-command" "flakes" ];
}

Nix Flakes を使い始める

プロジェクトを Flake として管理し始めるためには, Git 管理されたリポジトリの中で以下のコマンドを実行します.

nix flake init

すると,以下のような内容の flake.nix ファイルが生成されます.

{
  description = "A very basic flake";

  outputs = { self, nixpkgs }: {

    packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;

    packages.x86_64-linux.default = self.packages.x86_64-linux.hello;

  };
}

この flake.nix が, Flake のさまざまな設定を含む Nix ファイルです.
flake.nix は以下の要素を持つことができます.

  • description: この Flake の説明文
  • inputs: この Flake の依存パッケージ等
    • Git リポジトリ
    • ローカルディレクトリ
    • ほかの Flake
    • など
  • outputs: inputs の内容を受け取り,このプロジェクトに関連するさまざまな出力を返すような関数
    • 出力の例:
      • プロジェクトのビルド方法 (nix build で実行される)
      • プロジェクトに関連するスクリプト (nix run で実行される)
      • プロジェクトの開発用シェルにインストールするパッケージ (nix develop でシェルに入ることができる)
      • NixOS のシステム設定
      • など
  • nixConfig: このプロジェクト固有の Nix 設定

この flake.nix を使用する nix コマンドを実行すると, flake.lock ファイルが生成されます.
flake.lock ファイルは NPM の package-lock.json と似た役割を持ち, inputs に含まれる各種依存先のバージョンを固定しています.
ただし,リポジトリの git revision や SHA256 ハッシュが含まれており, package-lock.json よりも厳密な固定と考えることができます.

実用的な例

以下が,実際に自分があるプロジェクトで使用している flake.nix の一部です.

{
  description = "";

  # この Flake への入力です
  inputs = {
    # 公式リポジトリからパッケージをインストールします
    nixpkgs = { url = "github:NixOS/nixpkgs/nixpkgs-unstable"; };
    # Flake の作成を便利にするユーティリティ flake-utils を利用します
    flake-utils = { url = "github:numtide/flake-utils"; };
  };

  # この Flake の出力です
  outputs = { self, nixpkgs, flake-utils }: 
    # 本来 outputs は各システム(アーキテクチャ+OS)への出力を明示的に指定しなければなりませんが, flake-utils の機能を使って全システムを一度に指定します
    flake-utils.lib.eachDefaultSystem (system:
      let
        inherit (nixpkgs.lib) optional;
        pkgs = import nixpkgs { inherit system; };

        nodejs = pkgs.nodejs;
        yarn = pkgs.yarn;
        pipenv = pkgs.pipenv;
      in
      {
        # このプロジェクトの開発用シェルを出力します
        devShell = pkgs.mkShell {
          buildInputs = [
	    # `nix develop` で開発用シェルに入ると, Node.js,Yarn,pipenv を利用できます
            nodejs
            yarn
            pipenv
            python-ldap
          ];
        };
      });
}

このプロジェクトでは Node.js, Yarn, Pipenv を使って開発していたので,それぞれが開発用シェルで利用できるように設定しました [3]
また,今回は Docker を併用していたため設定しませんでしたが,ビルド方法を設定して nix build コマンドでビルドすることもできます.
このように,開発用シェル環境として使うだけでも便利なのではないかと思います.

以上が Nix Flakes の紹介です.

まとめ

この記事では, Liunx ディストリビューションである NIxOS と,プロジェクト管理ツール Nix Flakes について紹介しました.  
卒論で忙しいタイミングと被ってしまい,非常に簡単な説明しかできず残念です.
日本語の情報はまだ大変少ないため,また時間のある時にさらに詳しい紹介を行えたらと思います.

この記事をきっかけに興味を持ってくださる方がいると嬉しいです.
もしいたら,ぜひリアクションをください!

ここまで読んでいただいてありがとうございました.

脚注
  1. HTML ファイルが非常に大きいので、注意してください.読み込みも長いです. ↩︎

  2. Flakes にできることはとても多く,どういった分類のソフトウェアなのか明言されている場所を見つけられませんでした.本記事では「プロジェクト管理ツール」と呼んでおきます.どなたか正解が分かれば教えていただけると幸いです. ↩︎

  3. Nix の思想に沿うと Python のライブラリも Nix で管理するべきなのですが, Nix ユーザがプロジェクト内に自分しかいなかったため Pipenv を併用しました ↩︎

Discussion