Nixで作る個人開発環境
これまでWSL2 + Docker + VSCode体制で趣味開発をしていたが、下記に書く様に思うところがあったので、Nixを試してみることにした。雑多なメモ書きだが、断片的にでも誰かの参考になれば幸いである。
AS-IS
概要
- Docker + VSCode + DevContainer拡張で趣味開発環境を構築
- Windows機なため、Dockerと一口に言っても様々な登場人物がいる状態
- Windows 11
- ホスト
- WSL2
-
docker-desktop
と言うWSLディストリビューションが切られる - この上にコンテナが立ち上がる
-
- Docker Desktop
- ホスト側にデーモン
- このデーモンからの指示でWSL上にコンテナが上がる
- Windows 11
課題
- Docker Desktopが不安定
- WSL2があっても何かの拍子で不安定になることが多い
- 大体はWSL2のアップデートやDocker再インストール等で修復出来るが、一番最悪な時は作成イメージ・コンテナ等全部吹き飛んだ
- 障害ポイントの多さ
- Docker Desktopの不安定さにも繋がる内容かも
- ホスト + WSL2 + Dockerの複合構成なので、トラブルシュートが面倒
- 例えば仮想マシン側のリソースが枯渇した、と言う時にWSL2もDockerも疑う必要がある
- もっとシンプルに出来た方が疑うポイントも絞れる、快適になる
- ネイティブアプリ開発に激弱
- 出来なくは無いが面倒なポイントが多いとElectron開発を試す時に学んだ
- VSCodeロックイン問題
- あんまり大した問題では無いが、DevContainerサポートを加味するとVSCode一択だったので、他エディタで遊べる環境の方が楽しさ的にはベター
- ただ、VSCodeにぶっちゃけ不満は無いので、これはついでポイント
- あんまり大した問題では無いが、DevContainerサポートを加味するとVSCode一択だったので、他エディタで遊べる環境の方が楽しさ的にはベター
TO-BEを検討する
- ローカルは綺麗に保ちたい
- Dockerを利用した理由でもある
- 作るアプリ単位で環境もパッケージ依存関係も管理したい
- WSL2上で完結してこれが出来ればベスト
- WSL2 + VSCodeになればMSワールドに統一出来る意味でもスッキリする
- WSL2ならXサーバー機能も自前で保持している(WSLg)ため、ネイティブアプリ開発にも手を出せる
Nixで出来そう
Nix + Nix Flakesで実現出来そうと結論。
Nixは純粋関数型のパッケージマネージャーで、FlakesはNixの拡張機能として依存パッケージや開発環境等のプロジェクトのベース環境定義を提供する。
Nixはインストールしたパッケージを /nix/store/
の下に保持し、これらのパッケージはソースコードやビルド定義、依存関係等を含むプロジェクト定義情報をインプットに生成したハッシュによりプロジェクトと依存パッケージが関連付けられる。これはグローバル環境にインストールの上Pathも更新、と言ったローカル汚染を回避しており、かつ共有ライブラリで起きがちなバージョンコンフリクト(アプリAはv1、アプリBはv2と依存しているためにどちらかの挙動に支障が生じる、みたいな)の事象も回避出来ると、個人的に求めていた恩恵とも合致する。
ドキュメントを読んだ限りでは、これまでDockerfileを書いてDevContainerを立ち上げていた部分がFlakes作成に置き換わり、コンテナの代わりにNixによる開発シェルを起動する様な形に出来そうなイメージ。
Nixを試してみる
Windows 11 + WSL2でNixを試す。
Nix専用WSLディストリビューションを作る
トラブル防止も兼ねて、Nix検証を行うためのWSLディストリビューションを用意する。
// ubuntu-24.04をベースにnix-envディストリビューションを作る
$ wsl --export Ubuntu-24.04 C:\WSL\ubuntu2404.tar
$ wsl --import nix-env C:\WSL\nix-env C:\WSL\ubuntu2404.tar --version 2
// nix-envがあればOK
$ wsl -l
nix-env
でNixセットアップ
// nix-envディストリビューションに入る
$ wsl -d nix-env
// Nixインストール
$ sh <(curl -L https://nixos.org/nix/install) --daemon
// Nixインストール確認
$ nix --help
また、Nix Flakesは expetimental
の位置付けなため、~/.config/nix/nix.conf
で有効化の定義を記載する必要がある。
$ mkdir -p ~/.config/nix && echo "experimental-features = nix-command flakes" > ~/.config/nix/nix.conf
Nix Flakes作成
適当なworkディレクトリへ移動した上で、Nix Flakesの準備を行う。
// flakeテンプレート生成
$ nix flake init
flake.nix
のテンプレートが生成される。
{
description = "A very basic flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
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;
};
}
inputs
はFlakesが依存する外部のパッケージリポジトリ定義をURLとして記載、outputs
はプロジェクトが作成するビルドパッケージや開発シェル等の成果物定義に相当する属性セットを書く。名称に反してビルド定義に限らず、開発シェルの様な物も含むことが特徴と思う。開発もテストも本番ビルドもまとめて定義している意味では package.json
の scripts
に近いイメージ。
今回の趣旨は開発環境構築なため、上記テンプレートを弄り Node.js
アプリを開発出来る開発環境を作ってみる。
{
description = "A very basic flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# 動作システム
system = "x86_64-linux";
# 動作システムに関連するnix packageの読み込み
pkgs = import nixpkgs { inherit system; };
in {
# 開発シェル定義
devShells.${system}.default = pkgs.mkShell {
name = "nodejs";
buildInputs = [
pkgs.nodejs_22
];
};
};
}
devShells
を定義するだけ。この例では buildInputs
で依存するパッケージのNode.js 22系を指定している。
作成したFlakesの事前チェックと最新化を行えば準備完了。
// flake.nixの静的チェックを行い、問題無ければ最新化を実行
$ nix flake check && nix flake update
開発シェル起動
$ nix develop
exit
で開発シェルから抜けられるので、開発シェル内外で node
npm
コマンドを試して開発シェル内だけで有効化されていれば成功。
VSCode上での開発
VSCode上でLSPを効かせながら開発を行うには、nix develop
で構築された環境のランタイムや依存関係を認識する必要がある。
一番簡単なのは nix develop
した上で code .
でVSCodeを開いてしまうこと。開発シェル上でVSCodeが立ち上がるため、上記のやりたいことを即満たせる。
所感
- Nix + Nix Flakesで開発環境回りは実現出来た。構成もシンプル化成功
- WSL2上の環境なため、Dockerが不得手にしていたネイティブアプリ開発にも対応出来る様になった
- 最終的に出来上がる環境にも不満無しなので、このままプライマリの手段として使おうかなと思う
- 気になるポイントもいくつかあるので、ここは使ってみながら解消法を探したりする
- プロジェクトが巨大になると
nix
コマンドがめちゃくちゃ重い- Nixのハッシュ回りの仕様上、プロジェクト内のコード等を丸々インプットにハッシュ生成している様な挙動
- 開発途中で
flake.nix
アップデート等入ると若干キツイかも
- Nix独自の依存関係とLSPの相性
- 例えばPython環境を作る場合、
nix develop
で出来る環境にはpip
が無い - どこでPythonパッケージをインストールするかと言うと、
flake.nix
でwithPackages
を使い定義する - LSPはNixでPythonパッケージが管理されていることを認識していないはずなので、インポート出来たとしてちゃんとVSCode上で読み取ってあれこれしてくれるんだっけ
-
flask_cors
が駄目そうな挙動していた、要確認
-
- 例えばPython環境を作る場合、
- プロジェクトが巨大になると
P.S.
実は今回を機にNixOSにも興味が生まれて、Ubuntuを入れていたサブPCにNixOSを入れてみた。あんまり使い所をイメージ出来ていないが、NixOSの場合だと nixos-container
が使えたりもするのでこちらも色々遊んでみたいところ。実際のデプロイはどこかしらのPaaSにするのでNixOSのコンテナを作ったところで感はあるが、、
ちなみにOSセットアップは全部 configuration.nix
上で完結した。本当に宣言的な上、これを配布すれば再現も出来ると、Nixの凄さを味わった。日本語対応等の通常面倒な部分も含めてなので、宣伝文句に偽りは無いと感じる。
参考資料
下記の読書とChatGPTとの対話をベースにNix学習を行った。めちゃくちゃ捗って感謝の極み。
Discussion