最近の仮想化界隈を知る:VMWareからCoreOSまで

 仮想化の分野はどんどんと新しいものが出てくる。全部を実際に試すことは出来なくても、筋が良さそうなものについては、どういうものなのかある程度把握しておきたい。最近はちょっと忙しくてあまり情報収集ができてなかったので、追いつこうと思ってちょっと調べてみた。

ハイパーバイザ型仮想化とコンテナ型仮想化

 仮想マシンの歴史をたどると、メインフレームの方では随分と昔から使われている技術である、と出てくる。一方で、x86の世界ではそれほど歴史は長くなく、1999年にリリースされたVMwareがおそらく実用的な初の仮想マシン技術だろう。

 VMWareはハイパーバイザ型仮想化と呼ばれる技術で、上に乗るOS(ゲストと呼ばれる)に対して仮想的なハードウェアを提供する。ハイパーバイザ型も、どのレイヤで仮想的なハードウェアを提供するかで更に細分化されるらしいが、よく知らないので、ここではそこまでは踏み入らない。ハイパーバイザ型仮想化を行うソフトウェアとして有名なものは、VMWareの他にXen, KVM, VirtualBoxなどが挙げられる。

 ハイパーバイザ型仮想化の良い点は、ゲストに対してほぼ完璧な仮想化を提供できる点である。(USBなどを使おうとすると、実装上の問題にはよく遭遇するが、理屈では完璧な仮想化になっているはずである。)一方、ゲストOSで特権命令を実行する際にわざと特権違反を発生させてハイパーバイザが実行を代行するなど、パフォーマンス的には劣化がある。これを解決するためにIntel VTなどのテクノロジーが存在するが、オーバーヘッドを0にはできない。

 ハイパーバイザではないもうひとつの仮想化方式として、コンテナ型仮想化と呼ばれる技術がある。古くはchrootやjailが有名である。jailは筆者も以前に使っていたことがあるが、OSの自由度が高いようでいて、意外と低いというか、カーネル部分が自由に選べないのが制約として印象的だった。ちょうどx86からx86-64への移行期に使っていたこともあり、一見うまく動くようでいてゲスト側ではvalgrindがまともに動かない(カーネルは64bitなのだがゲストOSは32bitであり、しかもゲスト側では64bitカーネルで動いていることを全然意識してないっぽい)など、割とつらい目にあった記憶がある。定義からしておそらく当然だが、コンテナ型の仮想環境はどれも、コンテナ内で使えるカーネルが下側のカーネルと同じになるという制約を持つ。その代わり、パフォーマンスの面ではオーバーヘッドは非常に少ない。

Vagrantってなんなの?

 最近、仮想化関係で調べ物をしていると、Vagrantというソフトウェアがよく出てくる。これは私の理解するところでは、複数の仮想化ソフトウェアに1つの設定ファイルで対応できるようにした、抽象化ソフトウェアである。

 Vagrantが提供する価値としては、使いやすさの向上、という点が一番大きいのでは、と推測している。正直なところ、既存の仮想マシンのユーザーインターフェースは、あまり使いやすいものではない。使い勝手の向上というのは、地味なようでいて、エンジニアの生産性に大きなインパクトを与える。

Docker

 Dockerはlxcによるコンテナ型仮想化とaufsによる差分保存を組み合わせたソフトウェアである。Dockerの狙いは、システムの粗結合化である。これまでのウェブアプリケーションでは、複数のアプリケーションが同じサーバーで動作することがあった。例えば、アプリAとアプリBが同一サーバーで動いているものとしよう。AとBがライブラリCに依存してるとすると、ライブラリCをバージョンアップする際には、AとBの両方の動作検証をやり直す必要がある。また、動作検証の結果、Aに改修が必要になったとすると、Aが対応するまでBも古いライブラリCを使わなければならない。もしアプリAがプロプライエタリなもので、自分たちでいじれないものであったりする場合を想像すると、これは結構むずかしい問題である。

 もし、アプリAとアプリBが別の仮想OSで動いていたら、Bの方は気兼ねなくライブラリのバージョンを上げてしまうことが可能になる。これがDockerの提供する価値である。

 つまり、カーネルというのは滅多に仕様が変わらないので、ここを抽象化の壁にしてしまいましょう、というのがDockerのコンセプトであると言える。

Dockerの限界

 Dockerの大きな制約として、ホスト側のOSとコンテナ側のOSで、同じカーネルが動作する、という点がある。そのため、仮想化と考えるよりは、複数のアプリを分離独立して動かすためのもの、と考えておいた方が、後で困ることが少ないだろう。

CoreOS

 CoreOSは、Dockerを使って作った仮想OS上でのみアプリケーションを動かすことを想定したOSである。トップページにLinux Kernel + systemdとあるので、カーネルとsystemdしか使ってないと勘違いしてる(?)記述がいくつかのページで見受けられるが、実際にはCoreOSにもそれなりにユーザーランドのライブラリが入っている。でないとbashとかが動かない。CoreOSはChorme OSベースらしいが、Chrome OS自体はGentoo Linuxベースらしいので、CoreOSはGentooの子孫であると言える。

 ハイパーバイザ型の仮想化方式では、下の層を薄くしようという話はそれなりに多い。例えば、VMWare vSphere Hypervisorとか。しかし、コンテナ型仮想化で下側を薄くしようとする話は、私が知る限りではCoreOSぐらいしか聞いたことがない。(そういう専用ディストリビューションは、もっと古くからあってもおかしくないような気もする。情報求む。)

 CoreOSのもうひとつ重要な点として、etcdの存在がある。etcdは耐故障性を持ったkey-valueストアである。これを使ってクラスタ管理などをすることを目論んでいるみたいなのだが、現状だとまだその辺りで重大な機能が実装されている感じではない。とは言え、自分でちょっとコードを書けば、監視ソフトウェアの設定ファイル書き換えぐらいは簡単に実現できそうだ。

余談:etcdとかserfとか

 etcdの話が出てきたので、serfについても少し触れておこう。serfはvagrantと同じ作者が開発しているオーケストレーションツールで、具体的には、グループに新しいノードが追加・削除された際に、自動的に監視やロードバランシングの設定を書き換えるものである。serfは現在のノード情報をゴシッププロトコルで共有する。

 ゴシッププロトコルというのは自分が知っているノードに自分が持っている情報を一定の確率で送信するだけという比較的シンプルなプロトコルである。だいぶ適当なやり方なので、情報の一貫性が取れないタイミングが存在する。しかし、実装は簡単である。

 つまり、serfは強い一貫性を持つことをあきらめている、ということになる。用途を考えると強い一貫性は重要ではない、という判断なのだろう。

 一方、etcdは情報の共有にはRaftというコンセンサスアルゴリズムを使う。コンセンサスアルゴリズムについての説明は長くなるので適当に端折ってしまうが、要は状態を決めるのに多数決を使う、と思えばよい。(だろうと思う。)結果として、強い一貫性が得られるが、引き換えに、ネットワーク分離が発生した場合に値の更新が出来ないケースが出てきたりする。

 etcdは立ち位置としてはおそらくzookeeperが近い。コンセンサスアルゴリズムである特定の時点での値が決定できれば、あとはその上に皮をかぶせて色々な使い方ができる。例えば、serfでやろうとしているようなクラスタ管理みたいなこともできるだろうし、おそらく、CoreOSの開発チームはそれを狙ってetcdを開発している。etcdとzookeeperとの違いとしては、使っているコンセンサスアルゴリズム自体が違う点が挙げられる。個人的にはJavaのエコシステムがあまり好きではないので、そういう意味で、goで書かれているetcdには興味がある。

まとめ

 lxcやDockerなど、本稿で「コンテナ型仮想化」と分類したソフトウェアの公式ページを注意深く眺めると、「仮想化」という言葉が使われていないことがわかる。代わりに使われているのは「container engine」という呼び方である。実際、技術の性質的に仮想化というよりは、別の概念として捉えたほうが適切であるように思える。

 本記事で紹介した中では、Dockerが地味にエポックメイキングであるように思える。アプリ毎にjailで隔離しましょうや、というのはおそらくFreeBSD界隈では以前から存在したアイデアなのではないかと思うが、近年のハードウェア性能の向上や、それにともなうハイパーバイザ型仮想化からの揺り戻しとして、ちょうど支持を得られるタイミングなのではないかと思う。また、CoreOSは、Dockerが普及したら出てきそうな問題を先取りして解決しようと目論んでおり、「近い将来」を狙っているという点で素晴らしい。ソフトウェアを開発する時には、こういう視点が持てるようになりたいものだ。

このエントリーをはてなブックマークに追加

Latest articles