Linuxの起動はなぜsystemdに変わったのかリンクをコピーしました
Linuxマシンの電源を入れる。
やがてログイン画面が現れ、ネットワークがつながり、時刻が合い、必要ならSSHで接続できるようになる。一見すると連続した処理の流れに見えるが、Linuxカーネルが直接これらを起動しているわけではない。
カーネルが最初に起動するユーザー空間のプロセスには、PID 1が割り当てられる。PID 1は、必要なサービスを立ち上げ、状態を監視し、終了時には停止させる。この役割を担う仕組みをinitシステムと呼ぶ。PID-1の役割
現在の主要なLinuxディストリビューションでPID 1を務めているのがsystemdである。その前に広く使われていたのがSysV initだった。
SysVは「シスブイ」ではなく、由来になったAT&TのUNIX System Vに合わせて「システム・ファイブ」と読む。System V Release 1が登場したのは1983年である。Linuxに残った/etc/init.dやランレベルは、四十年以上前のUNIXの系譜を引いている。SysVの読み方
PID 1としての中心的な責務は共通しているが、その仕事の進め方は大きく異なる。
その入れ替わりを端的に物語る出来事が、2026年にあった。
16年の時を経て外された互換機構リンクをコピーしました
2026年3月17日(UTC)、systemd v260が公開された。
リリースノートには、次の変更が記されている。
Support for System V service scripts has been removed.
System V形式のサービススクリプトのサポートを削除した。
削除されたものには、SysV init向けの起動スクリプトをsystemdのサービスへ読み替えるsystemd-sysv-generatorが含まれる。v260の注意点
2010年に登場したsystemdにとって、SysVスクリプトとの互換性は欠かせなかった。当時のLinuxには、SysV init向けに書かれた起動スクリプトが大量に存在していたからである。systemdがどれほど優れていても、既存のサービスを起動できなければ、ディストリビューションは採用できない。
systemdは登場時からSysVスクリプトを読み取れた。2014年、その処理はPID 1本体からsystemd-sysv-generatorへ切り出された。SysV互換の沿革
systemdは、既存のスクリプトを新しい管理方式へ読み替える互換性を携えて普及した。
そのSysV互換が、登場から16年後に公式版から削除された。
これは、かつて標準的だったSysV initに代わり、systemdが事実上の標準になったことを象徴する出来事である。
何が置き換わり、なぜそこまで時間がかかったのか。まずはSysV initの仕組みから見ていこう。
起動処理をシェルスクリプトで書くリンクをコピーしました
LinuxでSysV initと呼ばれてきた起動方式は、initプログラム本体と、/etc/init.dやランレベルごとのスクリプト群からなる。実際の構成や規約にはディストリビューションごとの差があった。
SysV initでは、サービスごとに/etc/init.dへシェルスクリプトを置く。
ここでいうサービスは、SSH、ログ保存、時刻合わせなど、利用者が直接操作していない間も機能を提供し続けるプログラムである。長時間動き続けるプログラムは、デーモンとも呼ばれる。デーモンの語源
Debian系の仕組みを単純化すると、起動スクリプトの基本形は次のようになる。
case "$1" in
start)
start-stop-daemon --start --exec /usr/sbin/exampled
;;
stop)
start-stop-daemon --stop --exec /usr/sbin/exampled
;;
esacstartを渡せば起動し、stopを渡せば停止する。
実際のスクリプトには、設定の検査、PIDファイルの読み書き、ログ出力、再起動時の例外処理が加わる。サービス固有の処理を柔軟に書ける一方で、起動方法と管理方法が同じスクリプトへ入り込んでいった。
どのスクリプトをどの順番で実行するかは、ランレベルごとのディレクトリに置くリンク名で表した。
K01bluetooth
S10network
S30cron
S50sshSはStart、KはKillを表す。数字は処理する順番である。
S10networkがS50sshより先なら、ネットワークを準備してからSSHサーバーを起動できる。起動順序は、ファイル名の中に書かれていた。
この方式には、明快な長所がある。
シェルを知っていれば読める。特殊な環境には条件分岐を足せる。障害時にはechoを挟み、古き良きprintデバッグでどこまで実行されたかを調べられる。専用ツールを用いず、テキストエディタとシェルだけで修正できることは、故障したシステムを扱う場面では今でも魅力的である。
難しさは、自由に書かれたスクリプト群を、システム全体で一貫して管理することにあった。
サービスが起動したと判断する方法は、スクリプトごとに違う。PIDファイルを見るものもあれば、プロセス名を検索するものもある。依存関係はリンク名の数字、スクリプト内部の待機、ディストリビューション固有の規約に分散する。
シェルは何でも書ける。したがって、管理側はスクリプトを実行する前に、その結果を完全には把握できない。
それでも、ハードウェア構成が起動時に決まり、その後は同じ状態で長時間動くサーバーでは、大きな問題になりにくかった。
その前提が、2000年代から始まる変化によって崩れていく。
起動後も構成が変わるリンクをコピーしました
2000年代、起動の仕組みには二つの異なる要求が突き付けられた。
一つは、起動後の変化に追従することだった。
USB機器は電源を入れたまま接続され、無線LANは接続と切断を繰り返す。ノートPCはスリープし、別の場所で復帰する。仮想マシンでも、ハイパーバイザーが見せるディスクやネットワーク機器は変わりうる。仮想デバイス
Linuxカーネルでは2002年ごろから、プラグ・アンド・プレイ、電源管理、ホットプラグを共通に扱うデバイスモデルが整備された。カーネルは機器を認識すると、利用者空間へ追加や削除を通知する。動的ハードウェア
その通知を受け取る仕組みの一つがudevである。udevはカーネルから機器の変化を受け取り、/devのデバイスファイルを用意する。このudevは、後にsystemdプロジェクトへ統合される。
flowchart LR
H[機器を接続・取り外す] --> K[カーネルが変化を検出]
K -->|uevent| U[udevが通知を受け取る]
U --> D["/devを更新する"]もう一つの要求は、起動時間を短くすることだった。
番号順の起動では、互いに関係のない処理も前のスクリプトが終わるまで待ちやすい。独立した処理を見つけ、安全に並列実行できれば、その待ち時間を減らせる。
後期のディストリビューションでは、LSBヘッダーなどの依存情報から順序を生成し、並列起動する拡張も使われた。それでも、管理対象の中心が自由形式のスクリプトである点は変わらない。どの二つが本当に独立しているか、あるいは機器の到着をどのスクリプトが待つかを、管理側が確実に読み取ることは難しかった。SysVの並列起動
起動の遅さは分かりやすい症状だった。より大きな問題は、「起動時に構成を決め、命令を順番に実行する」というモデルだけでは、起動後も変わり続けるシステムを表しにくくなったことである。
これはLinuxだけの悩みではない。各OSは、変化への反応と安全な並列化を、それぞれの方法で試みた。
SolarisのSMFは、サービスを依存関係と状態を持つ管理対象として扱った。macOSのlaunchdは、サービス本体より先に通信を受け付け、必要になってからサービスを起動した。
Ubuntuで2006年に設計されたUpstartは、「ネットワーク機器が現れた」「ファイルシステムが利用可能になった」といったイベントに反応して処理を動かした。ここでいうイベントは、機器の追加やマウント完了のような「状態が変わった」という通知である。設計文書は、ネットワーク越しの/usrを使う場合、機器の認識、ファームウェアの読み込み、IPアドレスの取得までを待たなければマウントできない例を挙げていた。Upstartのイベント
固定された順番より、変化するハードウェアに適した考え方だった。
ただし、後にsystemdを設計するPoetteringは、イベント中心の設計だけでは、最終的にどの状態を実現したいのか、なぜある処理が起動したのかを追いにくいと考えた。
イベントへの反応と並列起動を両立させながら、目標とする状態も明示する。systemdは、その別の答えとして始まった。
バージョン0のsystemdリンクをコピーしました
2010年4月30日、Lennart Poetteringは「Rethinking PID 1」という長い文章を公開した。
本人による一文要約は、肩の力が抜けている。
新しいinitシステムを実験している。しかも楽しい。
のちに主要ディストリビューションの起動方式を変える提案は、実験的なプロジェクトとして公開された。設計はKay Sieversとの密接な協力から生まれ、当初から複数の開発者が関わっていた。
名称はすべて小文字でsystemdと書く。公式の説明では、Unixのデーモン名が小文字のdで終わる慣習に従った「system daemon」だからである。さらに公式サイトは、Dをローマ数字の500と読んで「System Five Hundred」と呼んでもよい、ただしそう綴ってはいけない、と冗談を添えている。systemdの命名
Poetteringが示した高速起動の原則は二つだった。
- 起動するものを減らす
- より多くを並列に起動する
Bluetoothを使わないなら、最初からbluetoothdを動かす必要はない。互いに独立したサービスなら、一つずつ起動する必要もない。
彼は自分のPCにあった起動スクリプトを数えた。grepが少なくとも77回、awkが92回、cutが23回、sedが74回呼び出されていたという。
一つひとつは小さな処理である。しかし、コマンドを呼ぶたびにプロセスが生まれ、初期化し、短い仕事を終えて消える。起動時には、その小さな処理が積み重なっていた。
半ば冗談として示された測り方もある。起動後にシェルでecho $$を実行し、自分のシェルに何番のPIDが付いたかを見る。Poetteringの環境では、Linuxが1823、macOSが154だった。
PIDの大きさだけで起動速度は決まらない。それでも、ログインできるまでにどれほど多くのプロセスが生まれたかは分かる。
発表時のsystemdは、まだ完成品ではなかった。バージョン番号は0。公開されたFedora 13のテスト用仮想マシンでは、パスワードがすべてsystemdに設定されていた。
Poetteringは、既存のinitへ機能を足すのではなく、起動処理の表し方から組み直した。
模式的に言えば、SysV initが扱ったのは実行する命令の列だった。
systemdが扱うのは、到達したい状態と、その状態に必要な対象の関係である。
flowchart TB
subgraph Sequential["単純化した番号順の起動"]
S1[起動開始] --> N1[network]
N1 --> C1[cron]
C1 --> H1[ssh]
H1 --> G1[起動完了]
end
subgraph Parallel["依存関係に基づく起動"]
S2[起動開始] --> N2[network]
S2 --> C2[cron]
N2 --> H2[ssh]
C2 --> G2[起動完了]
H2 --> G2
end番号順の列から、依存関係のグラフへリンクをコピーしました
systemdは、管理する対象をunitという共通形式で表す。
| unitの種類 | 管理するもの |
|---|---|
.service |
SSHやログ保存などのサービス |
.socket |
通信を受け付けるソケット |
.mount |
ファイルシステムのマウントポイント |
.device |
カーネルが認識したデバイス |
.timer |
時刻や間隔を条件にした処理 |
.target |
複数のunitを束ねた到達状態 |
ネットワークの準備を待って動くクライアントを単純化すると、unitファイルは次のようになる。
[Unit]
Description=Example network client
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/sbin/example-client
Restart=on-failure
[Install]
WantedBy=multi-user.targetExecStart=は起動するプログラムを示し、Restart=on-failureは異常終了時に再起動する方針を示す。
SysV initのスクリプトには、処理の手順を書く。
systemdのunitには、管理する対象の性質と、ほかの対象との関係を書く。
この違いは、Wants=とAfter=を見ると分かりやすい。
Wants=network-online.targetは、相手を起動対象へ加える要求関係である。After=network-online.targetは、両方が起動対象になった場合に、自分を後へ並べる順序関係である。
systemdでは、「必要であること」と「後であること」を別々に記述する。After=だけを書いても、相手を起動対象へ加えることはない。ユニットの依存関係
ここでnetwork-online.targetが表すのは、ネットワーク管理ソフトウェアが「利用可能になった」と判断した時点である。どの状態を利用可能とみなすかは構成によって異なる。外部との通信を待つクライアントには必要になることがあるが、接続を待ち受けるサーバーが常に待つべきものではない。ネットワーク利用可能状態
flowchart LR
Start[example-client.serviceを起動] --> Plan[必要なunitを集める]
Plan --> Example[example-client.service]
Plan -->|Wants| Network[network-online.target]
Network -. After .-> Examplesystemctl start example-client.serviceを実行すると、systemdは必要なunitを集め、順序を決め、競合を調べ、開始と停止を一つの計画として組み立てる。
起動処理は、番号順の列から、依存関係のグラフへ変わった。
通信相手の起動完了待ちを減らすリンクをコピーしました
依存関係をグラフで表しても、サービスAがサービスBと通信するなら、AはBの起動完了を待つ必要があるように見える。
systemdは、サービス本体より先にソケットを用意することで、この待ち時間を減らした。
ソケットは、プログラム同士が通信するためにOSが用意する窓口である。通常のサーバープログラムは、自分が起動してからソケットを開き、接続を待つ。
systemdでは、PID 1が先にソケットを開ける。
[Socket]
ListenStream=/run/exampled.sock
[Install]
WantedBy=sockets.targetクライアントが接続した時点でサービスがまだ起動していなくても、接続要求は待ち行列に入り、到着したデータもソケットのバッファに保持される。systemdはサービスを起動し、すでに開いているソケットを渡す。
sequenceDiagram
participant C as クライアント
participant K as カーネル
participant P as systemd
participant S as サービス
P->>K: ソケットを開く
C->>K: 接続する
K-->>P: 接続を通知する
P->>S: サービスを起動する
P->>S: ソケットを渡す
S-->>C: 応答するこれをソケットアクティベーションという。
この仕組みに対応したサービスでは、通信相手が完全に起動したかを独自に監視する必要がない。ソケットへ接続すればよく、サービスが準備中ならカーネルが接続を保持する。
これは、systemdがサービスの準備完了を一切待たないという意味ではない。Type=notifyでは、サービス自身がREADY=1を通知するまで起動完了とは扱われない。ソケットアクティベーションが減らすのは、主に通信相手側の待ち合わせである。サービスの準備完了通知
この考え方はsystemdの発明ではなく、inetdやlaunchdにも先例がある。
inetdは4.3BSDの時代から使われ、マニュアルでの肩書きはinternet super-serverだった。複数の通信口の待ち受け処理を一つのデーモンへ集約し、接続が来ると担当プログラムを起動する。systemdはこの古い発想を、ネットワークサービスだけでなく、同じマシン内の通信やサービス間の依存関係にも広げた。inetdの先例
ただし、起動の順序と通信の入口を整理しても、サービスを起動したあとの問題は残る。プロセスが子プロセスを作ったとき、どこまでを同じサービスとして扱えばよいのか。
PIDではなく、サービス全体を追うリンクをコピーしました
古いデーモンには、起動元から自分を切り離してバックグラウンドへ移る作法があった。
デーモンは起動時にforkし、親プロセスを終了させることがある。サービス管理側が最初に起動したプロセスは消え、別のPIDを持つ子プロセスが動き続ける。
flowchart LR
M[サービス管理側<br>把握したPID: 100] -->|起動| P[親プロセス<br>PID 100]
P -->|fork| C[子プロセス = デーモン本体<br>PID 101<br>バックグラウンドで動き続ける]
P -->|終了| X((PID 100は消滅))
M -. PID 100を追っても<br>デーモンには届かない .-> X
M -. 実際に動くPID 101を<br>別の方法で知る必要がある .-> Cそのため、デーモンはPIDファイルを残した。
/run/exampled.pid中には、現在動いている本体のPIDが書かれる。
この方式は、デーモンが正しいPIDを書き、終了時に削除し、古いファイルを残さないことを前提にする。PIDは再利用されるため、古い記録を別のプロセスと取り違える可能性もある。
さらに、デーモンが複数の子プロセスを作ると、一つのPIDだけではサービス全体を表せない。
systemdは、Linuxカーネルのcgroupを使ってプロセスをまとめる。
サービスから起動されたプロセスを専用のcgroupへ入れる。子プロセスはその所属を引き継ぐため、forkを繰り返しても同じサービスとして追跡できる。
flowchart TB
M[systemd]
subgraph G["cgroup: example.service"]
B[サービスの管理境界]
P[メインプロセス<br>PID 100]
C1[子プロセス<br>PID 101]
C2[子プロセス<br>PID 102]
B -->|所属| P
P -->|fork| C1
P -->|fork| C2
end
M -->|グループ単位で監視・停止・制御| B$ systemctl show systemd-journald.service -p MainPID -p ControlGroup
MainPID=612
ControlGroup=/system.slice/systemd-journald.service
$ systemd-cgls --unit=systemd-journald.service
Unit systemd-journald.service:
└─612 /usr/lib/systemd/systemd-journaldPIDは起動のたびに変わる。それでもControlGroupは、systemd-journald.serviceというサービス名に結び付いている。
systemdはこの単位でプロセスを停止し、CPUやメモリの使用量を制御できる。PIDファイルが一つのプロセスを指すのに対し、cgroupはサービスから生まれたプロセス群を管理対象にできる。cgroupによる管理
cgroup自体はsystemdの発明ではない。GoogleのPaul Menageらが2006年に開発を始めたころは、process containersやtask containersと呼ばれていた。しかし「container」という語は、namespaceで隔離された実行環境など別の意味でも使われ始めていた。そこで2007年にcontrol groupsへ改名され、Linux 2.6.24へ取り込まれた。cgroupの沿革
現在「コンテナ」を支える基礎技術として知られる仕組みが、systemdでは通常のサービスを追跡する境界にもなっている。
この設計は、systemdの方向性をはっきり示している。
systemdはUnix一般への移植性より、Linuxカーネルとの統合を選んだ。cgroupをはじめとするLinux固有の機能を使うことで、従来のinitより広い範囲を管理できるようになった。
同時に、Linux固有機能への依存は強くなった。この選択は、systemdの強みであり、批判の理由でもある。
この設計を掲げた実験は、短期間でディストリビューションの基盤へ進んだ。
バージョン0から一年で既定値へリンクをコピーしました
systemdの発表から約一年後、Fedora 15はsystemdを既定のinitシステムとして採用した。
リリースノートには、並列起動、ソケットやD-Busによるアクティベーション、cgroupによるプロセス追跡、マウント管理、依存関係のトランザクション処理が並んでいる。
2012年には、Arch Linuxも新規インストールの既定をsystemdへ変更した。
当初は従来のinitscriptsも残された。しかし数週間後、十分な開発資源を割けず、試験も行き届かないとしてsystemdへの移行が強く勧められた。Archの移行
既定値が変わると、単に初期設定が変わるだけではない。
既定値には重力がある。利用者も、試験も、文書も、保守の資源も、その周囲へ集まる。試験されない選択肢は壊れやすくなり、利用者が減り、さらに保守の優先度が下がる。
既定値は、将来どこへ開発資源を配るかを決める。
採用が進む一方、systemdプロジェクトはPID 1の外側へも範囲を広げていった。
ログに所属を持たせるリンクをコピーしました
サービスが動けば、ログが出る。
従来のsyslogでは、ログをテキストとして受け取り、/var/log以下のファイルへ振り分ける構成が一般的だった。
2012年、Fedora 17へjournalが導入された。開発の発端は、systemctl statusの末尾へ、そのサービスが出した直近10件のログを表示したいという要求だった。従来のsyslogだけでは、ログとunitを効率よく結び付けにくい。その小さな表示機能を実現するために、構造化されたjournalが作られた。journalの起源
テキストログは扱いやすい。システムの一部が壊れていても、catやgrepで読める。専用の検索ツールを必要としない。
一方、ログの本文だけでは分からないこともある。
Connection closed.どのサービスが、どのプロセスとして、どの起動時に出したログなのか。この一行だけでは判断できない。
systemd-journaldは、ログ本文と一緒に、PID、ユーザー、実行ファイル、所属unit、起動セッションなどをフィールドとして保存する。
_SYSTEMD_UNIT=ssh.service
_PID=1248
PRIORITY=6
MESSAGE=Connection closed.検索にはjournalctlを使う。
$ journalctl -u ssh.service -b
$ journalctl -b -p warning
$ journalctl --list-boots-uはunit、-bは起動セッション、-pは重要度で絞り込む。
ログファイルの置き場所を探すのではなく、「SSHサービスが今回の起動で出した記録」を問い合わせられる。
journaldは検索能力を高めたが、journalは単純なテキストファイルではない。専用の形式を専用のツールで読むことになる。
ファイルをそのまま読めることを重視するなら、従来のテキストログが分かりやすい。サービスとの関係を正確に検索できることを重視するなら、journalが便利である。
両者は併用できる。journaldが受け取った記録をrsyslogなどへ渡せば、構造化されたjournalと従来のテキストファイルの両方を残せる。journal自体の保存先も、設定に応じて/run/log/journalの揮発領域か、/var/log/journalの永続領域かが変わる。journalとsyslog
プロセスの所属を追い、ログにも所属を記録する。systemdは「サービス」を一貫した管理単位にしようとしていた。
initの範囲はどこまでかリンクをコピーしました
systemdはサービスの起動だけにとどまらず、.timer、.path、journald、logind、tmpfilesなどへ範囲を広げた。2012年には、デバイス管理を担うudevもプロジェクトへ統合された。udevの統合
この統合が利用者にも見えた例が、2013年のsystemd/udev v197で既定となったネットワークインターフェース名である。検出順で決まるeth0やwlan0は再起動後に入れ替わりうる。新しい方式は接続位置などからeno1やenp5s0のような安定した名前を作るが、短く親しみやすい名前ではなくなった。ネットワーク機器名
2013年、Poettering、Kay Sievers、Harald Hoyerがこの変更を紹介した講演の題名は、**What Are We Breaking Now?**だった。何かを改善すれば、慣れた名前が壊れる。その事情を開発側もよく承知していた。
ここで、systemdをどこまでinitシステムと呼ぶべきかという疑問が生じた。批判者はsystemdを「モノリシック」と呼んだが、journaldやlogindがPID 1の中へ詰め込まれているわけではない。それぞれ別の実行ファイルであり、別のプロセスとして動く。
flowchart TB
subgraph Project["systemdプロジェクト"]
P[systemd<br>PID 1]
J[systemd-journald<br>別プロセス]
L[systemd-logind<br>別プロセス]
U[systemd-udevd<br>別プロセス]
P <-->|連携| J
P <-->|連携| L
P <-->|連携| U
end争点は実行ファイルの数より、部品の交換しやすさにあった。同じプロジェクトで開発され、共通のAPIや設計を使う部品がほかのソフトウェアの前提になると、一つだけを別実装へ置き換えるにも周囲の対応が必要になる。
systemd側は共通の単位で管理できる利点を、批判側は共通基盤から一部だけを切り離す費用を見ていた。
共通の管理モデルは、unitによる権限制御にも広がった。
NoNewPrivileges=yes
ProtectSystem=strict
CapabilityBoundingSet=CAP_NET_BIND_SERVICE上の設定は、現在より強い権限を得ることを防ぎ、ファイルシステムの大部分を読み取り専用にし、使用できるLinux capabilityを絞る。
SysV initのスクリプトは、主にサービスをどう起動するかを記述した。systemdのunitは、起動したサービスをどの権限で、どの範囲に閉じ込めて動かすかも記述できる。
$ systemd-analyze security ssh.serviceこの評価は、サービス自体に脆弱性がないことを保証しない。unitがどの隔離機能を使っているかを、共通の基準で比較するためのものだ。サービスの権限制御
systemdプロジェクトの拡大には、一つの論理が通っていた。プロセス追跡、資源制御、権限、ログは、同じ「サービス」という単位で接続する。
だからこそ便利になり、だからこそ切り離しにくくなった。
この利点と懸念を抱えたまま、systemdはDebianの既定値をめぐる議論へ入っていく。
Debianを割った一票リンクをコピーしました
systemdをめぐる最大の論争の一つは、Debianで起きた。
2014年2月、Debianの技術委員会は、次期Debian 8 JessieのLinux版でsystemdを既定initとする決定を下した。
候補にはUpstart、OpenRC、sysvinitもあった。systemd側は依存関係を明示できる設計や採用の広がりを、Upstart側はUbuntuでの運用実績や移行の容易さを評価した。Linux固有機能や周辺機能との結合をどこまで受け入れるかも判断を分けた。Debianのinit論争
投票ではsystemdとUpstartが4対4で並んだ。Debian 8 JessieのLinux版で使う既定initは、委員長Bdale Garbeeの決裁票でsystemdに決まった。
決定をDebian利用者向けのメーリングリストへ転送したメールには、短い一言が添えられていた。炎上の始まり
Let the flames begin...
さあ、炎上の始まりだ。
予告は外れなかった。
同年には、Boycott systemdと名乗るサイトも現れた。新しいinitの必要性は認めながら、systemdを「第二のカーネル」に近いものと批判し、その統合の形を拒んだ。systemd不採用運動
争点は、どのPID 1を既定にするかだけではない。ほかのパッケージがsystemdを必須としてよいのか、systemd以外のinitを実際に使い続けられるのかも問題になった。設定上は別のinitを選べても、systemdを必要とするソフトウェアが増えれば、選べる環境は狭くなる。
2014年11月、Debian開発者全体の一般投票では、「一般決議は必要ない」が勝った。翌日、initへの依存を制限する案を推した技術委員Ian Jacksonは、論争に「疲れ果てた」と記して辞任した。同じ月には「Init Freedom」を掲げ、DebianからDevuanを分岐させる計画が発表された。
2015年には、Upstartを開発したUbuntu自身もsystemdへ移行した。ただし、当初はログイン後のユーザーセッションをUpstartが管理し続けた。OSの基盤は一度に総入れ替えされるのではなく、互換性を残しながら段階的に移る。
Upstartを生み出したUbuntuまで移行したことで、主要ディストリビューションの流れはほぼ固まった。Devuanは開発を続け、Alpine Linuxは現在もOpenRCを採用しているが、多数のパッケージを束ねる主要ディストリビューションのサービス管理は共通の形へ寄っていった。initの選択肢
systemdが共通の形へ寄せたものリンクをコピーしました
systemdが変えたのは、SysV initという一つのプログラムだけではない。
- サービスごとに異なる起動スクリプト
- ファイル名の数字へ埋め込まれた起動順序
- PIDファイルに頼るプロセス追跡
- デーモンごとに実装する再起動や権限削減
- 別々の場所へ散らばる状態とログ
systemdは、それらをunit、依存関係、cgroup、journalという共通の管理モデルへ寄せた。journalとsyslogのように従来の仕組みとの共存を残しながらも、ディストリビューションがサービスを扱う中心は移った。
一人の管理者から見れば、読み慣れたシェルスクリプトが大きな仕組みに置き換わった。数千のパッケージを束ねるディストリビューションから見れば、数千通りのスクリプトが、機械の読める共通形式へ置き換わった。systemdは後者の規模で問題を解いた。
状態確認、再起動、依存関係、プロセス追跡、ログ、権限制御を共通の方法で扱えることは、ディストリビューションにとって魅力的だった。同時に、systemdを前提とするソフトウェアが増えるほど、別のinitを維持する費用は高くなった。
これはsystemdだけの事情ではない。広く採用された標準は互換性を高める一方で、標準から外れる費用も高くする。
橋が外された日リンクをコピーしました
2010年のsystemdは、SysV initスクリプトを読み込めた。
当初はPID 1本体がスクリプトを読み、2014年からはsystemd-sysv-generatorが一時的なunitへ変換して、新しい依存関係の中へ取り込んだ。systemdが普及するには、この互換性が必要だった。
Fedoraが採用し、Archが続いた。Debianでは同数票の末に委員長が決裁票を投じた。Ubuntuは自ら開発したUpstartを手放した。
flowchart LR
A[1983<br>UNIX System V] --> B[2006<br>Upstart]
B --> C[2010<br>systemd v0]
C --> D[2011–2012<br>Fedora・Archが既定に]
D --> E[2014–2015<br>Debian・Ubuntuが採用]
E --> F[2026<br>SysVスクリプト互換を削除]利用者はsystemctlを使うようになり、パッケージ作者はunitファイルを書くようになった。デーモンも、自分でバックグラウンド化してPIDファイルを残す方式から、systemdが直接監視できる方式へ移っていった。
そして2026年、古いスクリプトを翻訳する仕組みが公式版から削除された。
移行のために架けられていた橋は、役目を終えたと判断されたのである。
v260では、互換性を一律に捨てない判断も見える。古いスクリプトを実行する機能は削除する一方、v258で一度削除されたrunlevel0.targetからrunlevel6.targetまでの名前は、ビルド時に選べる互換機能として復活した。ランレベル互換
互換性は、ある日まとめて消えるものではない。既存の操作や名前は残せる範囲で残し、維持する価値と費用を比べながら少しずつ整理される。
systemdを好むかどうかとは別に、この変化がLinuxへ残したものは大きい。
サービスをどう起動するか。
起動が完了したと、何をもって判断するか。
どのプロセスを同じサービスとして扱うか。
ログを単なる行として保存するか、サービスとの関係を持つ記録として保存するか。
OSの各部品を、どこまで共通の管理モデルへ組み込むか。
systemdは、これらを別々の問題として扱わなかった。一つのサービス管理基盤の中で答えようとした。
その範囲の広さが、systemdを普及させた。
同じ範囲の広さが、systemdを嫌う理由にもなった。
2026年のLinuxを起動すると、PID 1は何事もなかったようにサービスを立ち上げる。その背後には、SysV initのスクリプト、動的になったハードウェア、Upstartの試み、Fedoraの決断、Debianの一票、Devuanの分岐、そして十六年間維持された互換機構がある。
PID 1は一つのプロセスにすぎない。
だが、その一つがOS全体をどう見るかによって、Linuxの管理方法は変わった。
脚注
- PID-1の役割
LinuxのPID 1は孤児になった子プロセスの回収などを担い、シグナルの扱いにも通常のプロセスと異なる点がある。詳しくは
pid_namespaces(7)を参照。 ← - SysVの読み方
System Vは「System Five」と読む。1983年のSystem V Release 1についてはThe Open GroupによるUNIXの歴史と
standards(7)を参照。 ← - v260の注意点
ここで述べているのはsystemdプロジェクト公式版の変更である。ディストリビューションがv259以前を長期提供したり、互換機構を独自に残したりする可能性はある。手元の版は
systemctl --versionで確認できる。 ← - SysV互換の沿革
systemdは最初の公開時からSysV initスクリプトを設定源として扱っていた。最初の紹介記事を参照。2014年のコミットMove handling of sysv initscripts to a generatorで、その処理がgeneratorへ移された。 ←
- デーモンの語源
MITのFernando J. Corbatóによれば、彼のグループは1963年ごろ、熱力学の思考実験「マクスウェルの悪魔」になぞらえて
daemonという言葉を使い始めた。分子を休みなく選り分ける想像上の働き手から、表に現れずシステムの仕事を続けるプロセスを連想したのである。しばしば見かける「Disk And Executive MONitor」の略という説明について、Corbatóは自分には初耳であり、命名の由来ではないと答えている。Corbatóの回答とFreeBSDのThe BSD Daemonを参照。daemonは悪を意味するとは限らない古い語であり、ここでいうデーモンに悪魔的な意味はない。 ← - 仮想デバイス
Linuxのvirtio文書は、仮想マシン上のLinuxがハイパーバイザーの提供する仮想デバイスをPCIなどを通じて認識する仕組みを説明している。PCIのhotplug APIも、追加されたスロットを利用者空間へ公開して
ueventを送る。 ← - 動的ハードウェア
LinuxのDevice Modelは2002年に草案が作られ、プラグ・アンド・プレイ、電源管理、ホットプラグを目標としている。USB hotpluggingは、電源投入中の接続に対してドライバの探索や利用者空間の設定が必要になると説明する。
udevはカーネルから機器の追加・削除・状態変化を受け取る動的デバイス管理である。 ← - SysVの並列起動
- Upstartのイベント
Ubuntuの2006年のReplacementInit設計文書は、ネットワーク越しの
/usrを使うには、機器の認識、ファームウェア、接続確立、IPアドレス取得が必要になる例を挙げる。後年のupstart-events(7)にも、ファイルシステム、デバイス、電源状態などのイベントが記載されている。 ← - systemdの命名
- ユニットの依存関係
Wants=、Requires=とBefore=、After=が別の種類の関係であることはsystemd.unit(5)に定義されている。 ← - ネットワーク利用可能状態
network.targetとnetwork-online.targetの違い、後者を必要以上に使うべきでない理由は、systemd公式のRunning Services After the Network Is Upを参照。 ← - サービスの準備完了通知
Type=notifyのサービスがREADY=1で起動完了を通知する仕組みは、systemdのsd_notify(3)に定義されている。 ← - inetdの先例
- cgroupによる管理
カーネル側の仕様はControl Group v2、systemdから見た管理境界はControl Group APIs and Delegationを参照。 ←
- cgroupの沿革
cgroupの仕組みはLinuxカーネル文書にまとまっている。2007年には
process containersからcontrol groupsへ名称が変わり、その後Linux 2.6.24へ統合された。経緯はLWNのKS2007: ContainersとMerged for 2.6.24, part 2を参照。 ← - Archの移行
Arch Linuxは2012年11月4日のEnd of initscripts supportで、試験不足と資源・関心の不足を理由に、systemdへの移行を強く勧めた。 ←
- journalの起源
Lennart Poetteringはsystemd for Administrators, Part XIIIで、journal開発の当初の目的を、
systemctl statusへ直近10件のログを表示することだったと説明している。 ← - journalとsyslog
journalの保存先と従来型syslogデーモンとの連携は
journald.conf(5)に記載されている。 ← - udevの統合
Arch Linuxのsystemd-tools replaces udevは、systemdとudevが上流で統合されたことを2012年6月に告知している。 ←
- ネットワーク機器名
Predictable Network Interface Namesは、
eth0形式の問題とeno1、enp5s0などの命名規則を説明している。講演名はPoetteringのBrno 2013 Trip Reportに記録されている。 ← - サービスの権限制御
unitで指定できる権限制御は
systemd.exec(5)、systemd-analyze securityの評価範囲はsystemd-analyze(1)を参照。 ← - Debianのinit論争
Debianで提示されたsystemd側のPosition StatementとUpstart側のPosition Statementには、両案の利点、欠点、移行上の論点がまとめられている。 ←
- 炎上の始まり
文言はDebianメーリングリストの2014年2月12日のメールで確認できる。 ←
- systemd不採用運動
- initの選択肢
Devuanの現行リリースはRelease Information、Alpine LinuxによるOpenRCの採用はAlpine LinuxのOpenRC文書で確認できる。 ←
- ランレベル互換
v260ではSysVスクリプト実行機能を削除する一方、
-Dcompat-sysv-interfaces=yesでrunlevel[0-6].targetなど一部の名前を提供できる。詳細はCompatibility with SysVを参照。 ←