Open9

Nix改良に向けたあれこれ

hctaw_srphctaw_srp

https://zenn.dev/hctaw_srp/articles/3cd4e62e6fedc3

Nix駆動の開発環境整備の土台が出来たので、細かな気になるポイント解消を目指してあれこれやってみる。

環境は特段言及無ければWindows 11 + WSL2。一部サブPCのNixOS上の営みもあるかもなので、その場合は言及する。

hctaw_srphctaw_srp

nix コマンド高速化

事象

  • nix flake check 等のコマンドを打つ機会は多いが、一定出来上がったプロジェクト宛に実行するとめちゃくちゃ遅い
    • Electron + Vite構成のプロジェクト宛に time nix flake check を試すと4分かかった
real    3m59.841s
user    0m3.619s
sys     0m12.750s

理解

  • nix コマンドを実行すると、依存関係管理のためのハッシュ生成の意図でプロジェクトリソースをNixサンドボックス環境にコピーする挙動が走ると認識している
  • この挙動のため、プロジェクトが膨らむと必然重くなる

対策

  • .nixignore ファイルを作るとコピー対象のexclude定義が書ける
  • node_modules やビルド成果物はコピー対象から外してしまって良い気がするので除外してみると、ベンチマークが1分15秒程に短縮
  • 何をignoreするかの整備はもうちょっと練る必要があるが、対処は分かった
hctaw_srphctaw_srp

どこまでNix管理するか

  • 例えばPythonを利用する場合、nix develop でPythonを起動した時に pip は同梱されていない
  • 上記はNixの想定として、python3.withPackages(ps: with ps; [ XXX ]) の様な形でのインストールを考えている
  • ただ、上記はあまりにもNixに寄せた管理であり、下記の様な懸念・気になりポイントがある
    • VSCodeのLSP側でNixでインストールしたライブラリを認識出来ない可能性
    • Nixはあくまで開発環境として利用するだけで、デプロイ先はどこかのPaaSであれば pip の存在を前提にしたリソースを求められる。その場合に対応出来る?
    • ランタイム側のパッケージ管理は素直にランタイムに任せる方が素直なのでは

この場での結論

o3-miniとも討論して下記方針で進めようと思う。

  • Nixはあくまでも apt yum 等の役目を埋める物として定義(システムレベルパッケージ)
  • ランタイムレベルのパッケージはランタイム側のルールに沿う
    • Node.js -> npm
    • Python -> pip
  • 上記の分割は、元々行っていたDockerによる環境閉じ込めの単位とも一致するので運用上も違和感が無い
hctaw_srphctaw_srp

nixos-container の用途

これはNixOSの話になる。

nixos-container とは

NixOS上で systemd-nspawn ベースで作られた隔離環境を指す。
https://wiki.archlinux.org/title/Systemd-nspawn

これはOCI仕様に沿って作られたコンテナエコシステムであるDockerやPodmanとは明確に異なる。nixos-container はVM的なイメージで認識するのが近い気がする。

Nixの宣言的な書き味でOCIコンテナ定義を書ける様な記載があるが、あくまでもコンテナエンジンとしてPodmanを利用しているだけに過ぎないと理解なため、nixos-container の用途についてちゃんと考える様にする。
https://wiki.nixos.org/wiki/Docker

どこで利用するか

  • 開発目線では無さそう
    • nix develop で閉じた環境が作れるので、コンテナにする意味が無い
  • 再現出来る範囲がOS相当と思うと、OS宛の何かしらの検証環境にする、みたいな使い方になるのでは
  • でも、コンテナでやる必要性があるかは疑問。NixOSは configuration.nix で宣言的に定義を書けるので、切り戻しコスト自体相当低い
hctaw_srphctaw_srp

JPキーボード設定が再起動の度に解除される

NixOSの話。

事象

  • マシンを再起動するとJPキーボード設定が解除されUSキーボードに戻されてしまう
    • 無論GUI上から一度設定は切り替えている
    • services.xserver.xkb.layoutjp で定義している

理由

  • Waylandセッション上はGNOME側のスキーマ定義に沿ってキーボード定義がされる
  • services.xserver.xkb.layout はXorg向けの定義なため、Wayland側は無視する

対策

  • dconf定義を作成しGNOMEスキーマ側を制御する

実装

下記を参考に configuration.nix をアップデートする。
https://wiki.nixos.org/wiki/GNOME#dconf_settings

{
  programs.dconf = {
    enable = true;
    profiles.user.databases = [{
      # 上書き防止
      lockAll = true;
      # JPキーボードにセットする
      settings = {
        "org/gnome/desktop/input-sources" = {
          sources = [(lib.gvariant.mkTuple ["xkb" "jp"])];
        };
      };
    }];
  };
}
hctaw_srphctaw_srp

NixOSデスクトップ環境改善

これもNixOSの話。GNOMEベースにあれこれ改造する。

拡張機能インストール

例に漏れずこちらも configuration.nix で完結する。

{
  # GNOME有効化。ここはデフォルトでいずれもtrue設定されているはず
  services.xserver.displayManager.gdm.enable = true;
  services.xserver.desktopManager.gnome.enable = true;

  environment.systemPackages = with pkgs; [
    # gnome関連のパッケージたち
    gnome-tweaks
    gnome-shell-extensions
    gnomeExtensions.dash-to-dock
    gnomeExtensions.burn-my-windows
    gnomeExtensions.arcmenu
  ];
}

ここまで出来れば gnome-extensions-app コマンドでGNOME Shell拡張の設定GUIが立ち上がるため、ここで必要な有効化や設定等を行えばOK。

hctaw_srphctaw_srp

sudo パスワード有効時間を長くしたい

NixOSの話。例えば sudo でファイルオープンすると結構な頻度でパスワードを求められるので、流石にもうちょっと長く出来ないかと調査。

security.sudo を使う

https://github.com/NixOS/nixpkgs/issues/40157

{
  security.sudo = {
    enable = true;
    extraConfig = ''
      Defaults timestamp_timeout=15
    '';
  }; 
}

ドキュメントの通りだが、extraConfig の内容が sudoers に統合されるらしい。

hctaw_srphctaw_srp

Ulauncherがアプリとして登録されない

NixOSの話。ランチャーとしてUlauncherをインストールしたが、アプリとして登録されない事象が発生。

事象としては下記と一緒。
https://github.com/NixOS/nixpkgs/issues/214668

対応

  • ulauncher コマンドを打つと挙動することを確認したので、起動ショートカットを登録することにした。今は ctrl + L で立ち上がる様にしている
hctaw_srphctaw_srp

ipykernel インストール手順

Nix上でPython環境を構築の上、Zedで使えるREPL機能を有効化するべく ipykernel をインストールしようとしたが、どうやらNixがコードコンパイル系のライブラリ依存を追えない様でインストールに失敗したので、一工夫必要だった。

https://zed.dev/docs/repl#python

venv を利用する前提で下記記載。

手順

flake.nix 用意

flake.nix
{
  description = "Python REPL";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
  };

  outputs = { self, nixpkgs }:
  let
    system = "x86_64-linux";
    pkgs = import nixpkgs { inherit system; };
  in {
    devShells.${system}.default = pkgs.mkShell {
      buildInputs = with pkgs; [
        (python313.withPackages (ps: [ps.pip]))
      ];
      # activate venv if exists
      shellHook = ''
        if [ -d ./repl ]; then
          source repl/bin/activate
        fi
      '';
    };
  };
}

venv 準備

後述する fix-python がパッケージパッチ時にシンボリックリンクを辿らない様なので、--copies を渡してあげる。

$ python -m venv repl --copies

fix-python でコンパイルに必要なパッケージインストール

事象自体はある程度既知らしく、NixOS wikiでも記載があるが、あれこれ設定することも本筋で無いので venv 環境に必要パッケージをパッチしてくれる fix-python と言うCLIを使うことにする。
https://wiki.nixos.org/wiki/Python#Running_compiled_libraries
https://github.com/GuillaumeDesforges/fix-python

// 初回だけなので一時的にCLI有効化
$ nix shell github:GuillaumeDesforges/fix-python
$ fix-python --venv repl --libs libs.nix

fix-python がパッチしてくれるライブラリは gcc.cc glibc zlib だけなので、それ以外で必要な物は libs.nix に書く。今回は libstdc++ も必要だったので libs.nix はこんな感じ。

libs.nix
let pkgs = import (builtins.getFlake "nixpkgs") { };
in [
  pkgs.stdenv.cc.cc.lib
]

ipykernel インストール

下記に沿って本丸の準備。
https://zed.dev/docs/repl#python

$ source repl/bin/activate
$ pip install ipykernel
$ python -m ipykernel install --user --name repl --display-name "Python REPL"

補足

fix-pythonpip 等の行為は初回限定なので、一度環境が出来た後は shellHook で記載の様に venv を自動で起動することだけ自動化した。この上で zed なりでエディタ起動すればREPLまでスムーズに行ける。