分析Linux コンテナビジネスの Docker は、英国ケンブリッジのスタートアップ企業 Unikernel Systems を買収しました。同社は、独自 OS の開発で興味深い取り組みを行っています。
ユニカーネル アプローチでは、OS 上にアプリケーションを構築するのではなく、アプリケーションに合わせてカスタマイズされた独自の小さなオペレーティング システムを構築します。
これはサンフランシスコを拠点とする Docker にとって大きな成功である。なぜなら、Unikernel Systems は、パブリック クラウドやプライベート システムで仮想マシンを実行するために世界中で使用されているソフトウェアである Xen ハイパーバイザー プロジェクトの元開発者によって構成されているからだ。
LinkedInでUnikernel Systemのスタッフを調べてみると、CTOのAnil Madhavapeddy氏、David Scott氏、Thomas Gazagnaire氏、Amir Chaudhry氏といった、オープンソースのXenの開発に携わった、あるいは密接に関わっている人々が見つかります。チームは、小さな筐体でアプリを実行することについて、豊富な知識を持っています。
Unikernel の取り組みが興味深いのはなぜでしょうか。まずは Docker について思い出してみましょう。Docker は驚くほど使いやすいツールで、開発者やテスターがアプリケーションや、そのアプリケーションの実行に必要なコンポーネントを、他のコンテナとは分離された整理されたコンテナにパッケージ化することができます。
Linuxでは、コンテナの分離を維持するために、カーネル内のcgroupや名前空間といったメカニズムが使用されています。そのため、特定の構成でWebサーバーを立ち上げたい場合は、そのコンテナをビルド(またはダウンロード)して起動します。同様に、特定のツールチェーンが必要な場合は、必要なコンパイラ、ライブラリ、その他の依存関係を含むコンテナをビルドするか、イメージを探します。各コンテナは独立して管理されているため、あるコンテナ内の依存関係やプロセスが別のコンテナに干渉する心配はありません。
箱詰め... 1つのカーネル上で実行される3つのコンテナ。それぞれに
独自のアプリと依存関係が含まれています。
マシン上のすべてのコンテナは、同じLinuxカーネル(またはMicrosoftのOS上でDockerを実行する場合はWindowsカーネル)を共有します。Dockerは、それぞれ独自のカーネルとフル機能のOSを持つ仮想マシン全体を構築、起動、そして解体するよりも、使いやすく、効率的であることを目指しています。
各Dockerコンテナは、独自のプロセスツリーだけでなく、ベースから階層的に構築された独自のファイルシステムを備えています。コンテナには、特定のタスクを実行するために必要なソフトウェアのみが搭載されており、それ以上のソフトウェアは搭載されていません。そのため、これらのコンテナは仮想マシンよりもはるかに軽量であると考えられます。
Unikernel Systems は、その合理化をさらに一歩進めます。
カーネルという言葉は聞いたことがありますが、ユニカーネルとは何ですか?
ユニカーネル、つまりライブラリ型オペレーティングシステムは、約20年前から大学のコンピュータサイエンス学科の廊下や研究室に潜伏していました。ネットワークハードウェアベンダーは、信頼性の高い専門的なサービスを提供するために、ファームウェアにユニカーネルを採用してきました。
ユニカーネルはどのように動作するのでしょうか?コンテナについてこれまで述べてきたすべての要素(プロセス、依存関係、ファイルシステム、基盤となるモノリシックなホストカーネルとそのドライバー)を、あたかも単一のプログラムであるかのように、単一の空間に圧縮します。
混乱していますか? では、解決しましょう。典型的なLinuxマシンを例に挙げましょう。ターミナルを開き、ps auxを実行して、コンピュータ上で実行されているすべてのプロセスのリストを取得してください。これらのプロセス、つまり実行中のプログラムはそれぞれ独自の仮想アドレス空間を持ち、そこに独自のコード、変数、その他のデータ、そしてスレッドが存在します。この空間には、共有ライブラリやファイルがマッピングされます。この仮想空間の最上部、プログラムからはアクセスできない領域にカーネルがあります。カーネルは、まるで雲の上に座り、下にいる凡人を見下ろす神のように、すべてのプロセスの最上部に現れます。
プロセスがカーネルに何らかの処理を依頼する場合、システムコールを発行する必要があります。システムコールは、プロセッサの実行をプログラム内のコードから特権カーネル内のコードに切り替えます。カーネルが要求されたタスクを実行すると、プロセッサはプログラムに戻ります。
あるプロセスがネットワーク経由でデータを送信したいとします。送信する情報を準備し、必要なシステムコールを発行します。プロセッサはカーネルに切り替え、カーネルはデータをTCP/IPコードに渡します。TCP/IPコードはデータをパケット化し、イーサネットドライバに送ります。イーサネットドライバはデータフレームを物理回線に送り出します。最終的に、プロセッサはプログラムに戻ります。
ユニカーネルはこれらすべてを一つにまとめ上げます。カーネルは、アプリケーションにコンパイルされた別のライブラリ、あるいはライブラリ群に過ぎなくなります。結果として得られるバンドルは、完全にアクセス可能な同一のアドレス空間に配置されます。カーネルは、保護された独自のバブルに隔離されることはありません。
例えば、アプリケーションがネットワーク経由でデータを送信したい場合、カーネルへのシステムコールを発行して送信するわけではありません。プロセスとカーネル間でコンテキストスイッチは発生しません。代わりに、プログラムはネットワークライブラリ関数を呼び出します。この関数は、データの送信準備に必要なすべての作業を行い、基盤となるハイパーバイザーへのハイパーコールを実行します。ハイパーバイザーは、ネットワークハードウェアを制御してデータをネットワーク上に送信させます。
ユニカーネルモデルは、プログラムが必要とするカーネルの一部をカーネルの従来の保護空間からプログラムの仮想アドレス空間に引き抜き、ハードウェア固有の処理をハイパーバイザーに委ねます。これは、高性能な仮想化モデルである準仮想化の究極の結論です。
古いものと新しいもの...従来のモノリシックカーネル設計とコンテナ(左)、ハイパーバイザーまたはベアメタル上のユニカーネルアプリ
上に示されているように、カーネルの機能 (緑のブロック) は、各コンテナの基盤となるモノリシック ベースから、ハイパーバイザー上で実行されるアプリケーションに組み込まれたライブラリの断片に移動されます。
つまり、ユニカーネル アプリはアクションを実行するためにユーザー モードとカーネル モード間でコンテキストを切り替える必要がありません。コンテキスト切り替えは CPU クロック サイクルの観点から見ると比較的コストのかかる手順であり、ユニカーネルはこのオーバーヘッドを排除するため、無駄がなく効率的であることが期待されます。
また、ソフトウェアに必要なカーネル機能のみがコンパイルされ、それ以外の機能は破棄されるため、アプリは非常に軽量です。そのため、アプリの起動と停止は非常に高速で、リクエストが到着するとすぐにサーバーが稼働します。このモデルは、ソフトウェアに存在するセキュリティ脆弱性の数を減らす可能性さえあります。コードが少なければ、バグも少なくなります。
従来のPOSIXアプリケーションを実行したい場合は、rumpカーネルと呼ばれるものを使用できます。これは、Unix風アプリケーションをそのまま実行できるだけの通常のオペレーティングシステムを提供します。一例として、PHPからNginxまで、様々なパッケージをUnikernel環境で実行できるrumprunが挙げられます。Antti Kantee氏はrumpカーネルの開発に多大な労力を費やしており、Unikernel SystemsのエンジニアであるJustin Cormack氏も同様です。
注目すべき点の 1 つは、ハイパーバイザーが常に必要なわけではないということです。ランプ カーネル (サービスとしてのカーネルと考えてください) はハードウェア用のドライバーを提供できるため、ユニカーネル アプリをベアメタル上で直接実行できます。
あるいは、ドライバーライブラリをアプリに組み込むことで、ハードウェアと直接通信できるようにすることも可能です。これは、組み込みエンジニアリングプロジェクト、いわゆるIoTガジェットに特に役立ちます。Unikernel Systemsのソフトウェアは、ベアメタルARM互換プロセッサや、メモリ管理ユニットを搭載していないシステム(小型IoT機器に搭載されているようなハードウェア)上で動作します。
これらすべてにおいて、視点にもよりますが、一つ厄介な点があります。それは、ユニカーネルアプリケーションを信頼する必要があることです。個々のプロセス、コンテナ、仮想マシンを統制するための基盤となるカーネルを持つのではなく、ユニカーネルアプリケーションは、全体を制御する者がいない状態でマシンを共有する必要があります。ページテーブルやメモリ管理ユニットといったプロセッサに組み込まれたメカニズムを利用して、アプリケーションを分離する方法はいくつかあります。これらのアプリケーションを制御するモデルの構築は、ユニカーネルシステムズとDockerが取り組むべき課題です。
一方、信頼できないコードを実行する場合は、ソフトウェアが完全に分離された仮想マシンで実行することが必要になる可能性が高くなります。ユニカーネル アプリは、管理者によって設定および実行される信頼できるサービスであることが想定されています。
そういえば、これもまた難しい側面です。モノの管理です。Unikernelアプリは、まるでステロイドを投与されたマイクロサービスのようなものです。それらをデプロイし、連携させ、そしてそれをエレガントかつスケーラブルな方法で実現するのは、実に難しいのです。そして、ここでDockerの買収が関わってくるのです。