世界を動かす技術を、日本語で。

Nitro: 小さくても柔軟な初期化システムとプロセス監視ツール

2025年8月23日原文(git.vuxu.org)

概要

Nitro は、軽量なプロセス監督ツールで、Linuxの initプロセス (pid 1)としても利用可能。 組み込み機器サーバーコンテナ など多様な用途に対応。 RAM上で全状態管理 し、効率的なイベント駆動型動作を実現。 シンプルな ディレクトリ構成 によるサービス設定。 nitroctl によるリモート制御や、柔軟なログ管理機能を搭載。

Nitro の特徴と用途

  • Nitro は、極小サイズの プロセススーパーバイザー
  • Linuxの initプロセス(pid 1) としても動作
    • 組み込み機器デスクトップサーバー 用途
    • Linux initramfs 用init
    • Docker/Podman/LXC/Kubernetes などのLinuxコンテナinit
    • POSIXシステム上の 非特権監督デーモン

要件

  • Unixソケット 対応カーネル
  • tmpfs または書き込み可能な /run ディレクトリ

他システムとの比較優位性

  • 全状態をRAM管理、読み取り専用ルートfsでも動作
  • イベント駆動型、ポーリング不要
  • 実行時の動的メモリ割当ゼロ
  • ファイルディスクリプタ数の無制限使用なし
  • 自己完結型バイナリ (musl libc利用時は極小静的バイナリ)
  • 設定ファイルのコンパイル不要、サービスはスクリプトディレクトリのみ
  • 信頼性の高いサービス再起動
  • サービスごとのログ機能、ログチェーン構成も可能
  • システムクロック非依存
  • FreeBSD 上でも動作(/etc/ttys利用)

サービスディレクトリ構成

  • /etc/nitro (または指定ディレクトリ)内の各ディレクトリがサービス
    • setup: サービス開始前に実行、0で継続
    • run: サービス本体、プロセスが生存中はサービス稼働
    • finish: run終了後に実行、runの終了ステータスとシグナルを引数で受け取る
    • log: 他サービスディレクトリへのシンボリックリンク、ログパイプ処理
    • down: 存在時はデフォルトで起動しない
    • @で終わるディレクトリ: パラメータ化サービス用、nitroは無視
  • サービス名制限: 64文字未満、/・カンマ・改行禁止

特殊サービス

  • LOG: logシンボリックリンクがない全サービスのデフォルトログサービス
  • SYS:
    • SYS/setup: 他サービス起動前に実行
    • SYS/finish: シャットダウン時に実行
    • SYS/final: 全プロセス終了後に実行
    • SYS/fatal: 致命的エラー時に実行
    • SYS/reincarnate: シャットダウン時に実行、initramfs実装などに利用

パラメータ化サービス

  • @で終わるディレクトリ は直接起動せず、シンボリックリンクやnitroctlで起動
    • 例: agetty@/run + agetty@tty1 -> agetty@ シンボリックリンク
    • nitroctl up agetty@tty2 で agetty@/run tty2 実行

動作モード・ライフサイクル

  • 起動: gSYS/setup→全サービス起動(down指定除く)
  • サービス再起動: 異常終了時は最大2秒間隔で再起動
  • シャットダウン/再起動: nitroctl Reboot/Shutdown
    • SYS/finish→SIGTERM→最大7秒→SIGKILL→SYS/final→再起動/シャットダウン/終了

nitroctlによる制御

  • nitroctl [COMMAND] [SERVICE] 形式でリモート制御
  • 主なコマンド
    • list: サービス一覧・状態・pid・稼働時間・終了ステータス
    • up/down/start/restart/stop: サービス起動・停止・再起動
    • p/c/h/a/i/q/1/2/t/k: 各種シグナル送信
    • pidof: サービスのpid出力
    • rescan: /etc/nitro再読込
    • Shutdown/Reboot: システムシャットダウン/再起動

シグナルによる制御

  • SIGHUP: rescan
  • SIGINT: reboot
  • SIGTERM: shutdown(pid 1以外)

Linux initとしての利用

  • 自己完結型バイナリ、pid 1で直接起動可能
  • 必要に応じて /dev/run マウント
  • Ctrl-Alt-Delete で秩序立った再起動

Dockerコンテナinitとしての利用

  • 静的バイナリ なので容易にコンテナへコピー可能
    • 例:
      • COPY ./nitro /bin/
      • COPY ./nitroctl /bin/
      • CMD ["/bin/nitro"]
  • /run ディレクトリ必須
  • NITRO_SOCK で外部からnitroctl制御も可能

FreeBSDでの利用

  • /etc/ttys に以下を追加し、FreeBSD initで監督起動
    • /etc/nitro "/usr/local/sbin/nitro" "" on

ライセンス・著者

  • 著者: Leah Neukirchen(leah@vuxu.org)
  • ライセンス: 0BSD
  • 参考: daemontools, freedt, runit, perp, s6 など先行システムからの知見

Hackerたちの意見

s6と比べてどうなの?最近、Dockerコンテナでinitシステムをセットアップするのに使ったんだけど、nitroがいい代替になるのか気になってる。s6-overlayで設定しなきゃいけないファイルが多くて、思ったほど直感的じゃなかったんだよね。

s6はもっと複雑でリッチだね。Nitroやrunitはシンプルな代替になるだろうし、もしかしたらhttps://github.com/krallin/tiniもいいかも。

コンテナ内でinitシステムを動かすって話を見ると、いつも悩むんだよね。一方では、その用途を考えて設計されてるのはいいことだと思う。でも、単一のコンテナ内で、もっと適切にKubernetesやクラウド向けに設計されるべきものを、あまりにも複雑にしようとしてるのを見すぎた気がする。「人は結局やるだろう」って感じかな。でも、「もっと良くやる」ことで問題を広げるリスクがあるのか、古い解決策を残しておく方がいいのか、ちょっと迷ってる。

ロボティクスの経験から言うと、多くのコンテナは「これが元々はベアメタルで動いてたものをコンテナに移した」って感じで始まるんだ。プロセス間で無秩序なRPCが行われてるから、プロセスを別々のコンテナに分けるメリットはあまりないよ。Supervisor、runit、systemd、tmuxセッションなんかは、モノリシックな「アプリ」コンテナでいろいろなものを動かすための人気の選択肢だね。

そうだね、アプリケーションコンテナは「一つのことをやって、それをうまくやる」っていうUnixの哲学を守るべきだ。でも、もしDockerコンテナ内のプロセスが何らかの理由でフォークするなら、PID 1にはちゃんとしたinitが必要だよ。

コンテナ単位で料金を取るホスティングプロバイダーをいくつか使ったことがあるよ - Fly.io、Render、Google Cloud Run。価格の理由で、コンテナ内で複数のプロセスを動かしたくなることがよくあるんだ。

Distrustでは、セキュリティクリティカルなエンクレーブのユースケースで使われている、超シンプルなinitシステムをRustで書いたよ。https://git.distrust.co/public/nit

おそらくすごく良さそう(Nitより33%大きいけど)、でもREADMEにはビルド方法しか書いてなくて、インターフェースや動作については説明がないんだよね。

runitとの比較もしてみたいな。runitはすごくミニマルだけど、ほぼフル機能のinitシステムだし。制御ディレクトリや宣言的な依存関係がないこと、似たようなスクリプトのセット、ログの取り扱い方が似てるところが多いね。ページではrunitに触れられていて、chpstユーティリティを使うことも提案されてる。一つの対照的な特徴は、パラメータ化されたサービスで、いくつかの似たプロセス(agettyみたいなの)を一つのサービスディレクトリで制御できるのが面白い。もう一つの違いは、同じバイナリ(nitroctl)で再起動やシャットダウンをアクションとして実行できること。あと、nitroは単一のバイナリだけど、runitはいくつかあるからね。

Void Linuxを通じてrunitに慣れたけど、initシステムとしては機能してるものの、UIとドキュメントには不満が残る。特にログの設定が難しくて、サービスのために設定しようとしたときは本当にイライラした。シンプルで、まともなデフォルト、より良いドキュメント、直感的なUIを持つ他のものを試してみてもいいかな。

Leah NeukirchenはVoid Linuxコミュニティのアクティブなメンバーだから、ここでたくさんのクロスポリネーションが期待できるね。彼女がVoidでの使い方について何か書いてくれたら本当に素晴らしいと思う。

去年、runitで設定されたプロセスを動かしてた最後のサーバーを廃止したんだ。悲しい日だったな。15年前くらいにrunitサービスを書くことを学んで、それはすごくクールで理解しやすかったから、Linuxではそういうふうにサービスが動くものだと思ってた。そんで、5年間Linuxから離れてたら、戻ったときにはSystemdが主流になってた。悪い噂もいくつか聞いたけど、結局その議論の多くが悪意から来てることに気づいて、今では本当の理由が何なのかもわからなくなっちゃった。今はPi Zeroで、我が家のヒゲトカゲのビバリウムからカメラと温度データをストリーミングするサービスをいくつか動かしてるけど、systemdを使って設定するのはすごく簡単だったよ。それに、メインのOpenSuseデスクトップでemacsdを動かしたり、仕事用のノートパソコンでGoogle DriveのFuseソリューションを使ったりもできた。「標準的なものがあるのは実際いいことだね」って感じかな。

Hacker Newsで議論の続きを見る