今話題のいろいろなコンテナランタイムを比較してみた
[Docker Meetup Tokyo #26発表レポート]

Docker Meetup Tokyo #26での発表の様子

こんにちは、NTTの徳永です。今年度(H30年度)に入社し、新人としてコンテナ仮想化技術、特にコンテナランタイムの勉強に取り組んでいます。

2018年11月21日、Docker Meetup Tokyo #26が開催されました。私は登壇者として、今盛り上がりを見せているコンテナランタイム領域の動向について発表してきました。具体的には、Kubernetes®で利用可能な、7つのコンテナランタイムを高レイヤ・低レイヤに分類し、それぞれについて、機能、パフォーマンス、セキュリティ、開発動向を調査、比較した結果を示しました。本稿ではその概要を、補足を加えながら紹介します。

ぜひ下記の発表資料と合わせてご覧下さい。

当日の発表資料(詳細はこの資料をご覧ください)

概要

Kubernetesにおける基本的なアプリケーションの実行単位はPodと呼ばれます。Podは1つ以上のコンテナで構成され、各コンテナはそれぞれ独立の隔離環境を持ちます。また、各ノードではKubernetesのコンポーネントのひとつであるkubeletが動作し、Podやコンテナの実行管理を司ります。

群雄割拠なコンテナランタイム領域

kubeletはPodやコンテナの管理こそ行うものの、それらの隔離環境を直接的には操作しません。これを担うのがコンテナランタイムと呼ばれるコンポーネントです。コンテナランタイムがkubeletからPodやコンテナ等を操作する命令を受け、カーネルの機能等を用いながら隔離環境を作成したり、それを直接操作します。

今、コンテナランタイムの領域はまさに群雄割拠の様相を呈しています。つい先日もAWS re:Invent 2018でVMベースのコンテナランタイムFirecracker™が Amazon Web Servicesから発表されました(ただしKubernetesにはまだ対応していません)。それぞれのコンテナランタイムには、機能やパフォーマンスなど様々な点で違いがあります。また、コンテナランタイムによってコンテナ隔離環境の実現手法も異なるため、その選定はセキュリティに直接的に影響すると考えられます。

コンテナランタイム領域を分類する2つのレイヤ

今回はそれらのうち、Kubernetesで利用可能で、私がよく耳にする7つのコンテナランタイムを調査しました。調査にあたってはコンテナランタイムを以下の2つのレイヤに分類し、各レイヤごとに比較を行いました。

高レイヤランタイム
CRIランタイムやハイレベルランタイムとも呼ばれます。kubeletからの命令をunix socket経由で受付けます。このAPIはCRIと呼ばれます。本稿では、CRIで定義された命令をCRI命令と呼びます。高レイヤランタイムはCRI命令に従い、イメージの取得や展開、ネットワークのセットアップなどを行います。コンテナの直接的な操作のためには低レイヤランタイムを実行します。今回はcontainerd®、CRI-Orkt™に着目し、それぞれの機能、パフォーマンス、開発動向を比較しました。

低レイヤランタイム
OCIランタイムやローレベルランタイムとも呼ばれます。OCI™ Runtime Specificationと呼ばれる標準仕様があります。高レイヤランタイムによって実行され、カーネルの機能等を利用しながらコンテナの隔離環境を作成したり、それを直接操作します。今回はrunc™、gVisorNabla ContainersKata Containersに着目し、セキュリティ、パフォーマンス、開発動向を比較しました。

特にパフォーマンスについては、critoolsを用いて各CRI命令の処理時間を計測し、定量的に比較しました。詳しい比較は発表資料をご覧ください。なお、CRI命令の処理はあくまでもコンテナランタイムが行うことのごく一部に過ぎず、それ単体ではコンテナランタイムそのものの性能を決定し得ないことに留意ください。

以下に調査結果の概要を述べます。詳細は発表資料をご覧ください。

高レイヤランタイム

高レイヤランタイムはkubeletからunix socket経由でPodやコンテナ操作のCRI命令を受け、それを処理します。

高レイヤランタイムの概要

containerdMobyプロジェクトCNCFプロジェクトに属しており、現在活発に開発が進められている高レイヤランタイムです。元々はDocker®の一部だったものが独立したという経緯を持ちます。他の高レイヤランタイムと比較しても多機能で、イメージのpush機能や、Go APIを持ちます。今回測定したCRI命令処理のパフォーマンスは、全体的にCRI-Oと同等に良好でした。

CRI-OはKubernetes Node SIGで開発が活発に進められています。containerdとは対照的に、当初からKubernetes指向で開発されてきました。機能面もcontainerdとは対象的で、kubeletからの要求を処理するために必要な最低限の機能のみ備えています。パフォーマンス測定結果はcontainerdと同等に良好でした。しかし、パフォーマンスボトルネックとなるCRI命令には違いもありました。具体的には、containerdはコンテナの実行(StartContainer)で時間がかかるのに対し、CRI-Oはコンテナの作成(CreateContainer)で時間がかかることが分かりました。

rktはCoreOSによって開発が進められてきたランタイムです。最近は開発が落ち着きつつあります。他のコンテナランタイムとは異なり、隔離環境を直接操作する低レイヤ機能を持ちます。これは、stage1-imageと呼ばれる専用のイメージで実現されます。このイメージを入れ替えることで、namespaceやVMなど様々な方式による隔離環境を利用できます。rkt自体はデーモンとしては動作せず、CRI命令を待つためにソケットを監視することもしません。それを担うのは、rktletと呼ばれるデーモンです。rktletは、unix socketを監視しながらCRI命令を待ち、命令に応じて適切にrktを実行します。パフォーマンスについては、特にPodの起動やコンテナの作成と削除が、他の高レイヤランタイムに比べ低い結果となりました。

低レイヤランタイム

低レイヤランタイムは高レイヤランタイムから実行され、隔離環境を作成したりそれを直接操作します。OCI Runtime Specificationと呼ばれる標準仕様があります。隔離環境の作成には、ユーザ空間カーネル、unikernelのようにOSレイヤの先進的な技術が積極的に採用される傾向があり、技術的な観点から見ても大変面白い分野です。

低レイヤランタイムの概要

runcはOCIによるコンテナランタイム実装です。namespace、cgroups、pivot_rootに加え、AppArmorやSELinux、seccompのようなLinuxのセキュリティ機構を活用することで、システムへの影響の小さいセキュアなコンテナを作成することができます。最近では、rootless実行にも対応しています。今回測定したCRI命令処理のパフォーマンスについては、他の低レイヤランタイムに比べ概ね全体的に高い結果となりました。

gVisorはGoogleによるコンテナランタイムです。ユーザ空間カーネルと呼ばれる技術を用いています。アプリケーションが発行するシステムコールは、ユーザ空間に実装されたgVisorのシステムコールハンドラでサービスされます。gVisor自体はseccompにより50種程度に制限されたシステムコールのみを発行します。さらに、各アプリケーションはgoroutineとして実行され、go runtimeによりユーザ空間でスケジューリングされます。このように、本来カーネルが担う機能の一部をユーザ空間に再実装することで、カーネルとコンテナ間の隔離を強めようとしています。パフォーマンスは概ね良好ですが、今回計測したptraceモードでは、runcやNabla Containersには多くのCRI命令処理で劣る結果となりました。

Nabla ContainersはIBM®によるコンテナランタイムで、unikernel技術を応用しています。アプリケーションはホストカーネルのユーザ空間でsolo5プロジェクトunikernelとして動作します。solo5プロジェクトにおけるunikernelは低レイヤ層にtenderと呼ばれるハードウェア仮想化ソフトウェアを用い、ハイパバイザ上で実行されます。Nabla Containersでは、このtenderをコンテナランタイムに置き換えており、unikernelをユーザ空間で実行します。コンテナランタイム自体は7種のシステムコールのみを発行するため、カーネルとアプリケーション間は強く隔離されるといえるでしょう。ただし、アプリケーションはあらかじめrumprunなどによりunikernelとしてsolo5向けにコンパイルされている必要があります。パフォーマンスを測定してみると、Podやコンテナの起動についてはruncと同等かそれ以上に高くなりました。開発は他のコンテナランタイムに比べて落ち着いているものの、まだ開発が始まってから日も浅いため、今後の動向に注目する必要がありそうです。

Kata ContainersはOpenStack® Foundationによるコンテナランタイムです。PodごとにVMを作成し、VM内でコンテナを実行することでカーネルとコンテナ間の隔離を強めます。各コンテナは、ホストカーネルと分離されたVM内のゲストカーネル上で動作するため、原理的には他の低レイヤランタイムに比べてホストカーネルとコンテナ間の隔離は強いと考えられます。しかし、パフォーマンスについては、VM起動を伴うPod作成のパフォーマンスが他のランタイムに比べて数倍遅いという結果が出ました。

まとめ

本発表では7つのコンテナランタイムの概要とそれぞれの違いを示しました。採用技術も幅広く、全体像の掴みにくいコンテナランタイム領域への理解の一助となれば幸いです。

また、スライドの末尾には、solo5 unikernelベースのDockerイメージを、既存のイメージを使わずにrumprunを用いてスクラッチから作成する手順を記述しました。興味のある方は是非試してみてください。

おわりに

私たちNTTは、オープンソースコミュニティで共に活動する仲間を募集しています。ぜひ弊社 ソフトウェアイノベーションセンタ紹介ページ及び、採用情報ページをご覧ください。