基礎●●○○○

カーネル

Kernel ・ かーねる

OSの中核としてハードウェアを直接管理し、プロセスにCPU・メモリ・入出力を配分する特権プログラム。

✦ 30秒で試す — 航海アプリは、画面に1文字出すことさえ自分ではできない1台のサーバでコンテナを100個動かすと、動いているカーネルは?予想してみる

概要

カーネルはOSの中核をなすプログラムで、ハードウェアを直接管理し、その資源を各プログラムに配分する「支配人」です。CPU・メモリ・ディスク・ネットワークといった限られた資源を、複数のプロセスが奪い合わないように取り仕切り、どのプログラムにいつCPUを使わせ、どれだけのメモリを割り当てるかを一手に決めています。OSという言葉が指す範囲は広く、GUI やコマンド群まで含みますが、その一番奥で常に動き続けている特権的な部分がカーネルです。

カーネルの決定的な特徴は、ハードウェアに直接触れることを許された唯一の存在である、という点です。ふだん私たちが書くアプリケーションは、ファイルを開くのもネットワークにつなぐのもメモリを確保するのも、自力ではできません。すべてカーネルに頼んで代行してもらいます。アプリが自分から頼むときの正式な入口がシステムコールです。

普段カーネルの存在を意識することは少ないかもしれませんが、Linux カーネルのバージョン、dmesg に流れるメッセージ、コンテナがホストと共有しているもの——こうした場面の中心には常にカーネルがいます。障害調査を突き詰めると、最後はこの層に行き着きます。

なぜ生まれたか

初期のコンピュータには、資源を仲介する存在がありませんでした。プログラムはハードウェアを直接叩き、メモリの好きな番地を読み書きし、ディスクやプリンタを自分で制御していました。この「全員がハードウェアに直接手を伸ばせる」世界では、1本のプログラムのバグが機械全体を巻き込みます。誤ったアドレスに書き込めば他のプログラムやOS本体のデータを破壊し、無限ループに陥ればCPUを独占して他が一切動けなくなる。1台の計算機で複数の仕事を安全に走らせることが、原理的にできなかったのです。

そこで考え出されたのが、「ハードウェア管理を一人の仲介者に独占させ、他のプログラムはその仲介者に頼む立場に落とす」という設計です。CPUに特権モードという仕組みを設け、そこで動く仲介者=カーネルだけがハードウェアを直接操作でき、アプリケーションは制限された権限しか持たないようにしました。行儀の悪いプログラムが暴れても、その被害を自分の領域の中に閉じ込められる。1960年代のタイムシェアリング計算機で育ったこの「触れる者を一人に絞る」発想が、マルチタスクで安定して動く現代のコンピュータの土台になりました。

詳細

カーネル空間とユーザー空間

カーネルによる保護の実体は、CPUが持つ「特権レベル」というハードウェア機能です。多くのCPUは少なくとも2段階の権限を持ち、最も強い権限(特権モード。x86 では Ring 0、ARM では EL1)で動くコードだけが、ハードウェアの直接操作や全メモリへのアクセスを許されます。カーネルはこの特権モードで動きます。一方、アプリケーションは弱い権限(ユーザーモード。Ring 3、EL0)で動き、危険な命令を実行しようとするとCPUがそれを弾いてカーネルに制御を移します。

この権限の違いに対応して、メモリ空間も「カーネル空間」と「ユーザー空間」に分かれています。ユーザー空間で動くプロセスは、カーネル空間のメモリを覗くことも壊すこともできません。制御がユーザー空間からカーネルに移るのは、次の3つの場合に限られます。アプリが自分から頼むシステムコール、デバイスやタイマが知らせてくる割り込み、そしてゼロ除算や、仮想メモリでまだ載っていないページに触れたときのページフォールトのような例外です。どの場合も、飛び込む先はカーネルがあらかじめ登録した入口だけで、アプリがカーネルの内部に好きな場所から入り込むことはできません。この入口の管理があるからこそ、カーネルは「誰が何を要求してきたか」をすべて検査でき、不正な操作を水際で止められます。

ユーザー空間(弱い権限・ユーザーモード)プロセスAプロセスBプロセスCカーネル空間(特権モード)システムコールの入口カーネルプロセス管理・メモリ管理・入出力・ファイル操作する割り込みハードウェア(CPU・メモリ・ディスク・NIC)
ユーザー空間とカーネル空間の二層。アプリが頼む入口はシステムコール、デバイスの知らせは割り込みとして下から入る。ハードウェアに触れるのはカーネルだけ

カーネルの主な仕事

カーネルの担う仕事は、大きく4つに整理できます。第一にプロセス管理です。多数のプロセスやスレッドを短い時間で切り替えて(スケジューラが担当)、1個のCPUコアをあたかも複数あるように見せます。切り替えのきっかけの多くは、タイマーや周辺機器からの割り込みです。第二にメモリ管理です。仮想メモリという仕組みで、各プロセスに「自分だけがメモリ全体を占有している」ように見える独立空間を与えます。第三に入出力です。デバイスドライバを通じてディスクやネットワークカードを操作し、機種ごとの差異を吸収して統一的なインターフェースにします。第四にファイル管理です。ディスク上のただのビット列を、ファイルシステムとしてディレクトリとファイルの扱いやすい形に抽象化します。

アプリケーションの「ファイルを開く」も「メモリを確保する」も「別のマシンと通信する」も、最終的にはシステムコールを通して、この4つの機能のどれかに帰着します。

モノリシックカーネルとマイクロカーネル

カーネルをどう作るかには、大きく2つの設計思想があります。モノリシックカーネルは、プロセス管理・メモリ管理・ドライバ・ファイルシステムまで、上で挙げた機能をすべて一つの大きな特権プログラムに詰め込む方式です。すべてがカーネル空間の中で直接関数を呼び合うため高速ですが、その分カーネルは巨大になり、一つのドライバのバグがカーネル全体を落とし得ます。1991年に始まった Linux はこの方式の代表で、機能をモジュールとして後から読み込んだり外したりできる工夫を加えています。

対するマイクロカーネルは、カーネル空間には最小限の中核(プロセスの切り替え、メモリの基本管理、プロセス間のメッセージのやり取り)だけを残し、ドライバやファイルシステムはユーザー空間の普通のプロセスとして動かす方式です。アプリがファイルを読みたいときは、カーネルを経由してファイルシステムのプロセスへメッセージを送り、返事を受け取ります。壊れたドライバはそのプロセスだけを再起動すればよく、障害を封じ込める堅牢さが魅力ですが、機能同士がメッセージを介するぶん往復の手間が増えます。MINIX 3・QNX・形式検証された seL4 などがこの系統です。両者の中間をとる「ハイブリッドカーネル」(macOS の XNU、Windows NT 系など)も広く使われています。1992年には、MINIX の作者 Andrew Tanenbaum と Linus Torvalds がニュースグループ上でどちらの設計が優れているかを論じ合い、「Tanenbaum–Torvalds 論争」として今も語り継がれています。

モノリシックカーネルユーザー空間アプリカーネル空間(特権モード)スケジューラメモリ管理ドライバファイルシステムネットワークスタック全機能が特権空間の中で直接呼び合うマイクロカーネルユーザー空間 — FS やドライバもプロセスとして動くアプリFSドライバネットカーネル空間(特権モード)中核だけ切り替え・基本メモリ・メッセージ① 依頼② FS へ届ける機能同士はカーネル経由のメッセージでやり取りする
モノリシックとマイクロの対比。前者は全機能を特権空間に詰め、後者は中核だけを残して、ドライバやファイルシステムをユーザー空間のプロセスに追い出す

コンテナはカーネル共有、VM はカーネル別

カーネルという単位は、現代のインフラで「隔離の境界がどこにあるか」を理解する鍵になります。仮想マシン(VM)は、ハードウェアそのものを仮想化し、その上でゲストOSが自前のカーネルを丸ごと起動します。VM ごとにカーネルが独立しているため隔離は非常に強いですが、OS 一式を起動するぶん重く、立ち上がりも遅くなります。

一方、コンテナはカーネルを共有します。1つのホストカーネルの上で、namespace(見える範囲の分離)や cgroup(使える資源量の制限)というカーネルの機能を使って、プロセスから見える世界を区切っているだけです。だからコンテナは「隔離を強化されたただのプロセス」であり、一瞬で起動でき軽量です。反面、全コンテナが同じカーネルを共有するため、カーネルの脆弱性はすべてのコンテナに影響し、コンテナの中から特権を奪ってホストへ抜け出す「コンテナエスケープ」の足場にもなります。そのため、信頼できないコードを動かす場面では、コンテナごとに軽量な VM を立てる Firecracker や、カーネルの代役をユーザー空間で動かす gVisor のような、境界を二重にする仕組みが使われます。「カーネルを別に持つか、共有するか」——この一点が、VM とコンテナの重さ・速さ・隔離の強さの違いを説明します。

試問

アプリ(弱い権限で動く普通のプログラム)が動いている最中に起きる、9つの出来事が並んでいます。カーネル(OS の中核。画面・ディスク・ネットワークなどの機械を直接操作できる唯一のプログラム)へ制御が移るのは、アプリが自分から頼むシステムコールと、頼まなくても機械や CPU の側から飛び込んでくる割り込み・例外のときだけです。それぞれの出来事で、制御がどう動くかを見分けます。

✦ 命題挑戦中

9つの出来事を、アプリだけで済むか、アプリが頼んでカーネルへ移るか、頼まずにカーネルへ移るかで仕分けよ

アプリだけで済むカーネルは出てこない
アプリが頼むシステムコール
頼まずに移る割り込み・例外

項目を選んでから、入れる箱を選びます