はじめに
先日以下のQiita記事を書いたのですが、公開した後にコンテナランタイムについて全然書いていないことに気付いたので、今度はコンテナランタイムの動向について整理してみたいと思います。
Docker・Kubernetes周辺の動向を整理してみた件
また、最近 containerd・cri-o・gVisor などの名前を聞くことが増えたのですが、それぞれの違いを自分が理解できていなかったので、自己学習の目的としてもWeb上の情報などを元に整理したいと思います。
コンテナ仕様の標準規格
コンテナランタイムを整理する前に、OCI(Open Container Initiative)とCRI(Container Runtime Interface)の概要について説明します。
OCI(Open Container Initiative)とは
Open Container Initiative(OCI)とは、コンテナのランタイムとイメージ関連のオープンな業界標準を作成するため、2015年6月にDocker社などの複数の企業により設立された、現在はLinux Foundation傘下のオープンソース団体です。
2018年7月時点のメンバは以下の通りで、Amazon社・Microsoft社・Google社・Facebook社など、ほとんどの大手テクノロジー企業が参加しています。
※引用: https://www.opencontainers.org/about/members
2017年7月に「OCI v1.0」が策定され、コンテナランタイムの標準仕様である「Runtime Specification」と、コンテナイメージの標準仕様である「Image Format Specification」がリリースされています。
また、2018年4月にはコンテナイメージ配布の標準仕様を策定する、「Distribution Specification」プロジェクトに着手しています。
※参考: https://www.opencontainers.org/blog/2018/04/09/distribution-spec-is-here
CRI(Container Runtime Interface)とは
CRI(Container Runtime Interface)とは、2016年12月にKubernetes 1.5からαリリースされた、kubeletとコンテナランタイムが通信するためのI/Fを規定したものです。
CRIの概要は以下の図の通りです。
※引用: https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/
CRIが規定される以前は、コンテナランタイム側がkubeletの内部構造を理解しなければならず、新しいコンテナランタイムをKubernetesに組み込むことは非常に障壁の高いことでした。しかし、CRIが規定されることにより、KubernetesはDocker以外のコンテナランタイムを組み込み易くなりました。
また、OCIとCRIの関係は以下の図の通りです。
CRIがkubeletとHigh-Levelのコンテナランタイム間の通信のI/Fを規定しているのに対して、OCI(Runtime Specification v1.0)はHigh-LevelのコンテナランタイムとLow-Levelのコンテナランタイム間の通信のI/Fを規定しています。
突然High-LevelとLow-Levelのコンテナランタイムが出てきたので混乱されるかもしれませんが、High-LevelなコンテナランタイムはCRIで規定されたI/F経由でkubeletから呼ばれるコンテナランタイムであり、Low-LevelなコンテナランタイムはOCIで規定されたI/F経由で呼ばれるコンテナランタイムであると、ご認識いただければ大丈夫だと思います。
コンテナランタイムの種類
containerd
containerdとは、元々はDocker内部で利用されDocker社が開発していましたが、2017年3月にCloud Native Computing Foundation(CNCF)に寄贈されたコンテナランタイムです。
2018年5月に「containerd v1.1」が正式リリースされ、CRIにネイティブ対応することが発表されました。
また、コンテナランタイムにDockerを使用していた場合の内部構造は以下の通りで、DockerはCRIにネイティブ対応していないため、dockershimというブリッジを介して通信が行われていました。
次に、2017年12月に正式リリースされた「containerd v1.0」では、CRI-Containerdをブリッジしていましたが、CRIにネイティブ対応はできておりませんでした。
これに対して、「containerd v1.1」ではCRIにネイティブ対応することにより、Kubernetes(kubelet)から直接containerdを操作できるようになりました。これにより、CPU・メモリの使用率が削減されるとのことです。
※引用: https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/
rkt
rktとは、CoreOS社(2018年1月にRed Hat社が買収)がDockerランタイムの代替として開発し、2017年3月にCloud Native Computing Foundation(CNCF)に寄贈されたコンテナランタイムです。
Dockerと比較してシンプルなプロセスモデルであることや、Podをネイティブで扱うことができる点などが特徴です。
Dockerとrktのプロセスモデルの比較は以下の通りです。
※引用: https://coreos.com/rkt/docs/latest/rkt-vs-other-projects.html
cri-o
cri-oとは、Kubernetes Incubator Projectとして開発され、CRIとOCIの2つの標準に準拠した軽量コンテナランタイムで、2017年10月にv1.0が正式にリリースされました。
コントリビューターにはRed Hat社・Intel社・IBM社などが含まれていますが、コミュニティ主導のオープンソースプロジェクトとして開発されています。
cri-oのアーキテクチャは以下の通りです。
CRIに準拠していることからkubeletと直接連携し、OCIとも準拠していることからLow-LevelのコンテナランタイムとしてrunCと連携しています。
※引用: http://cri-o.io/
runC
runCとは、OCIを実装したLow-Levelのコンテナランタイムです。前述したcontainerdやcri-oにおいて利用されています。
gVisor
gVisorとは、Google社が開発しオープンソースして公開されている、準仮想化のような仕組みを用いて安全性を高めたコンテナランタイムです。
従来のコンテナランタイムは、コンテナ間でOSカーネルを共有しているため、コンテナからOSのシステムコールを直接呼び出せることにより、セキュリティ問題を引き起こしやすい構造になっています。
これに対して、以下の図の通り独自のgVisorレイヤを提供することにより、「サンドボックス化されたコンテナ(Sandboxed containers)」を実現しています。
※引用: https://github.com/google/gvisor
また、gVisorはOCIにも準拠しているためrunCと置き換えることが可能であり、cri-oと組み合わせてKubernetesと連携することが可能ですが、2018年7月時点ではプロダクション環境での利用は推奨されていません。
※参考: https://github.com/google/gvisor
Kata Containers
OpenStack Foundationにより開発され、コンテナ間でカーネルを共有せず分離レベルを高めたコンテナランタイムであり、2018年5月にv1.0が正式リリースされています。
登場した背景はgVisorと同じであり、従来のコンテナランタイムのセキュリティを向上する目的で開発されました。
Kata Containersのアーキテクチャは以下の通りです。
OSカーネルの共有を行わず、軽量なハイパーバイザーを用いてコンテナの分離レベルを高めて、コンテナのセキュリティを向上しています。
また、OCIとCRIに準拠しているため、従来のコンテナランタイムと同様に利用することができます。
まとめ(所感)
本記事では、コンテナランタイムの動向について整理してみました。
前回の Docker・Kubernetes周辺の動向を整理してみた件 の記事と同様に、今回の記事も作成して率直に疲れました。
オーケストレーションツールはKubernetesがほぼデファクトスタンダードとなっていますが、OCI・CRIという標準規格が策定されたことにより、コンテナランタイムはまだまだ色々な動きがありそうですね。