🦔

Nix Flakeで作る開発環境管理

2024/12/16に公開

1. はじめに

前回の記事で、Nixの基本的な概念と特徴について書きました。
今回は実際にNix触ってみて、実践的な開発環境の構築と管理方法について書いていきます。

主に以下のポイントについて書いていきます。

  1. Flakeを活用した環境管理

    • 再現性の高い開発環境の構築
    • 依存関係の明示的な管理
  2. 環境の階層化

    • 共通の開発ツール(Git, Dockerなど)の基盤環境
    • 言語固有の環境(Node.jsなど)の追加
    • 環境の分離と継承の実現
  3. 実践的な環境切り替え

    • 開発環境間の切り替え
    • CLIでの簡単な操作

2. Nixのインストールと設定

まずはMacOSにNixをインストールしていきます。

2.1 Nixのインストール

公式のインストールスクリプトを使います。

sh <(curl -L https://nixos.org/nix/install)

インストーラーが行うこと

Nixのインストーラは、マルチユーザーモードでシステムに以下のような変更を加えます。

  • システムユーザーとグループの作成
  • /nix ディレクトリにNixのインストール
  • 設定ファイルを/etc/nixに作成
  • bashrczshrcの更新
  • Nixデーモン用のLaunchDaemonの作成

💡 Tip: インストール中にsudoの使用許可を求められますが、これはNixを適切にセットアップするために必要です。

インストールが終わったら

インストール後は環境を読み込む必要があります。

. /etc/zshrc

ターミナルを再起動することでもNixの環境が自動的に読み込まれます。

最後にインストールできたか確認します。

nix --version

Nixのバージョンが表示されればインストール成功です。

2.2 Flakeを使えるようにする

Flakeは、Nixで開発環境を管理する新しい方法です。

  • 依存関係を明確に定義できる
  • 環境の再現性が高い
  • 設定がシンプルで分かりやすい

まだ実験的な機能という位置づけですが、開発環境の管理には既に広く使われています。
Flakeを使うためには明示的に有効にする必要があり、~/.config/nix/nix.confに以下の設定を追加します。

experimental-features = nix-command flakes

ファイルがない場合は、以下のコマンドで作れます。

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

設定が完了したら、NixのFlake機能を使えるようになります。

3. プロジェクトの構築

3.1 基本構造

プロジェクトのディレクトリ構造を以下のように作成します。
今回はNodeJSの開発環境を構築することを想定しています。

ディレクトリの作成

まず、プロジェクト用のディレクトリを作成します。

mkdir -p nix-craft
cd nix-craft

Flakeの初期化

Nixのflake機能を使用して、プロジェクトを初期化します。

nix flake init

これにより、デフォルトのflake.nixが生成されます。

追加ディレクトリの作成

mkdir -p shells
mkdir -p environments/node

最終的なディレクトリ構造は次のようになる想定です。

nix-craft/
├── flake.nix          # Flakeの設定
├── flake.lock         # 依存関係のロックファイル
├── shells/            # 共通の開発環境設定
│   └── shell.nix
└── environments/      # 個別の開発環境設定
    └── node/
        └── shell.nix  # Node.jsの開発環境設定

ディレクトリの役割

  • flake.nix: Flakeの設定ファイル
  • flake.lock: 依存関係とそのバージョンを固定
  • shells/: 共通の開発ツール(Git, Dockerなど)の基盤環境
  • environments/: 言語固有の環境(Node.jsなど)の追加

この構造により、共通の開発ツールと言語固有の環境を柔軟に管理できます。

3.2 共通開発環境の設定

共通の開発ツールを定義する shells/shell.nix を作成し、プロジェクト全体で共有できる開発環境を構築します。

shell.nixの作成

shells/shell.nix ファイルを以下の内容で作成します。
今回の共通ツールはGitとDockerのみとします。

{ packages ? import <nixpkgs> {} }:

packages.mkShell {
  # 基本的な開発ツール
  buildInputs = with packages; [
    git
    docker
  ];

  # ホストの環境と完全に分離する
  # この指定がないと、ホスト側の環境を継承するので継承をさせないための設定
  pure = true;

  shellHook = ''
    echo " Welcome to nix-craft development environment"
  '';
}

pure環境について

pure = trueにすることで以下のようになります。

  • ホスト環境のパスやツールをあえて使えなくする
  • Nixで明示的に指定したツールだけを使えるようにする
  • そうすることで相互に干渉しない環境を構築できる

この設定により、開発環境の再現性と信頼性を高められます。

3.3 Node.js環境の設定

共通環境を継承しつつ、Node.js固有の開発環境を構築します。

Node環境用のshell.nixの作成

environments/node/shell.nixを作成します。

{ packages ? import <nixpkgs> {} }:

let
  # 共通の設定を読み込む
  baseShell = import ../../shells/shell.nix { inherit packages; };
in
packages.mkShell {
  # 基本シェルから設定を継承
  inherit (baseShell) pure;

  # 基本シェルから buildInputs を継承
  buildInputs = baseShell.buildInputs ++ (with packages; [
    nodejs_22 # Node.js v22
    nodePackages.pnpm # pnpmを追加
  ]);

  shellHook = ''
    ${baseShell.shellHook}
    echo "Node.js development environment activated"
    echo "Node.js version: $(node --version)"
    echo "pnpm version: $(pnpm --version)" 
  '';
}

この設定は以下のようなことを行います。

  • 共通環境(Git, Docker)を継承
  • Node.js v22とpnpmを追加
  • 環境変数などの分離設定も継承

3.4 Flakeによる統合

これまでに作成した共通環境とNode.js環境をFlakeで統合します。

flake.nixの作成

nix-craftディレクトリの直下にflake.nixを作成します。

{
  description = "Development environments managed with Nix";

  inputs = {
    # 公式リポジトリからパッケージをインストールします
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    # Nixのflakeで便利なユーティリティ関数を提供するライブラリ 
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }: 
    # eachDefaultSystemは各プラットフォーム向けの設定を自動生成
    # systemにはx86_64-darwin, aarch64-linuxなどが自動的に渡される
    flake-utils.lib.eachDefaultSystem (system:
      let
        # legacyPackagesは従来のnixpkgsパッケージ群を指す
        # 現在でも標準的に使用され、多くのパッケージがこの形式で定義されている
        # flakeのコンテキストではパフォーマンス面でも推奨される方法
        packages = nixpkgs.legacyPackages.${system};
      in
      {
        devShells = {
          default = import ./shells/shell.nix { inherit packages; };
          node = import ./environments/node/shell.nix { inherit packages; };
        };
      }
    );
}

この設定により共通環境がdefaultとして定義され、Node.js環境がnodeとして定義されます。

依存関係の固定

Flakeの依存関係を固定するために、以下のコマンドを実行します。

nix flake update

これによりflake.lockファイルが生成され、プロジェクトの依存関係のバージョンが固定されます。

3.5. 環境の使用方法

ここまでの準備でflake.nixがあるディレクトリで以下のコマンドを実行することで開発環境を使うことができます。

nix develop

特に指定がなければdefault環境が使われます。

Node.js環境の使用

Node.js開発環境を使うには以下の通りです。

nix develop #node

実行すると以下のような出力が表示され、環境が準備されます。

Welcome to nix-craft development environment
Node.js development environment activated
Node.js version: v22.10.0
pnpm version: 10.9.0

この環境ではdefault環境(GitとDocker)に加えてNode.jspnpmが使えます。

環境を抜ける

開発環境から抜けるのは exit コマンドで行います。

4. まとめ

Nix Flakeを使った開発環境管理により、以下のようなメリットがありました。

  • 共通の開発ツールと言語固有の環境を分離して管理できる
  • pure環境による分離で、ホストや別の環境間との干渉を防ぐ
  • 依存関係はlockファイルで管理され、再現性を確保できる

今回作成した環境は基本的な例ですが、この構造を基に必要な開発環境を追加していくことができます。

株式会社スタメン

Discussion