ORNEW

なぜDockerからrktに移行するべきか?

Facebook にシェア
Pocket

なぜDockerからrktに移行するべきか?

コンテナ仮想化エンジンであるDockerは、今や一般の開発者まで浸透しつつあると言えます。当然私もDockerを使ってきましたが、最近Dockerではなくrktへ移行しました。rktはCoreOS社の開発するアプリケーションコンテナエンジンです。なぜDockerをやめたのか、なぜrktを選んだのかをご説明しましょう。

募るDockerへの不満

Dockerが素晴らしいプロダクトであることは事実です。コンテナ仮想化技術がここまで発展した背景にDockerの存在があったのは間違いありません。しかし、Dockerには多くの問題点があるのもまた事実です。バージョンアップとともに改善したもの・改善を見せているものもありますが、僕がDockerをやめた背景として全て書きます。

  1. イメージの検証システムの脆弱性
  2. イメージの共有手段の柔軟性
  3. コードベースの肥大
  4. ベンダーロックと移植性
  5. 既存のLinux初期化システムとの調和性
  6. 特権分離と脆弱性

rktでは、これらの問題が大きく改善されています。

イメージの検証システムの脆弱性

Dockerはバージョン1.8でDocker Content Trustが導入されました。それ以前のバージョンでは、イメージを検証する機構がなく、危険なイメージもデーモン上で容易に実行できていました。

では、今のバージョンなら安心でしょうか。確かに、Docker Content Trustにより、改ざんされたイメージファイルを取得したりすれば検知してくれるようになりました。しかし私はDockerを安全だとは思っていません。

第一の理由に、この機能が未だにデフォルトでオンになっていないことが挙げられます。オンになってない時点で役に立っていません。きちんとDockerの正しい知識を持った人しか有効にしていないでしょう。

第二に、そもそも、改ざんする以前にイメージ自体が悪意をもって作成された場合、この機構は役に立ちません。重要なのは「ユーザが」その発行元を確認できること、そしてその発行元を「ユーザが」信用することです。この仕組みでは、署名がされたイメージであれば何ら警告無くイメージをダウンロード・実行できます。つまり検出できるのは第三者による改ざんだけであって、担保されるのはイメージそのものの信用ではありません。Docker Content Trustとは名ばかりです。

rktでは、イメージを取得する場合はデフォルトで署名の検証が行わます。言い方を変えれば、必ず署名が必要になります。署名を検証し改ざんが検出されなかったとしても、署名元が信用できるかどうかをエンジンが勝手に判断することはありません。信用する場合は必ずユーザがその意志を明示する必要があります。

イメージの共有普段の柔軟性

Dockerではイメージの共有に専用のレジストリが必要でした。或いは、Docker Hubで有料のプライベートレジストリをホストする必要がありました。

rktは簡単です。なぜならrktアプリケーションコンテナイメージはただのtarballなのですから。FTPでも、HTTPSでも、既存のネットワークファイルシステムですぐに共有できます。

2016年9月になり、DockerもコンテナイメージのデータレイアウトがOpen Container Initiative準拠になりました。これによりレジストリを使わずとも共有が可能になりましたが、まだ1年も経っておらず、十分に活用されている状況ではありません。

初期から既存システムとの統合を図って設計されたrktは、App Container Image Discoveryなどのより進んだHTTPベースの分散イメージ共有の手段などを積極的に利用することが出来ます。

コードベースの肥大

Dockerバージョン1.11までの実装はすべての機能を単一のモノリシックプログラムファイルに追加しており、バージョンアップを重ねるごとにコードラインが増加し続けました。肥大したコードからたくさんの脆弱性が生まれたのは既知の通りです。バージョン1.11以降からcontainerdによるコンテナ起動アーキテクチャに変わり、コードもかなり改善されてはきていますが、依然として複雑なコードを抱えています。

これに対しrktは、機能が異なるベンダによって独立したバイナリとして開発されるモジュールアーキテクチャを使用します。ベースコードはできるだけ小さくして攻撃の表面積を減らす。これは、たとえetcdのようなサブコンポーネントが危険にさらされても、そのプログラムがアクセスできるものにしかダメージが及ばないことを保証します。分割された各ステージはプラグ可能で、とても高い構成可能性を持っています。

ベンダーロックと移植性

rktはApplication Container(AC)と呼ばれるオープンソースコンテナ形式を使用します。ACは、策定中のオープンスタンダードであるOpen Container Initiative(OCI)のベースとなっており、互換性があります。また、OCIのコアメンテナにはrktの開発元であるCoreOS社のメンバがたくさん在籍しています。rktを使用して作成されたイメージは、標準仕様に基いて別のコンテナシステムに簡単に移植できます。

Dockerも2016年の9月にOpen Container Initiativeを採用しました。上辺を見ればイメージについては問題ありませんが、Dockerはオープンスタンダードを採用したのがあまりにも遅く、積み上げてしまった資産が大きいぶん開発は鈍重です。

既存のLinux初期化システムとの調和性

Dockerは集中デーモン型で、各コンテナはデーモンへの強い依存の元に構成されてしまうため、既存のサービスシステムに統合するのは容易ではありません。

rktは集中デーモンを持たず、独立したプロセスとして稼働します。これにより既存のupstartやsystemdなどのinitシステムと簡単に統合することができます。

また、DockerはイメージをDockerfileという独自のファイルで構築します。宣言的な定義は可読性においてしばしば便利ではありますが、自動化や汎用化には妨げとなります。rktでは、ステートレスなコマンドベースでイメージを定義できます。

特権分離と脆弱性

よりクリティカルな問題に踏み込みます。繰り返しになりますが、Dockerはバージョン1.11でアーキテクチャを大きく変更しました。それ以前のDockerの仕組みに大きな欠陥があったからです。

以前のDockerのプロセスモデルはDocker Engineという特権デーモンを核とする構造でした。この中央集権型のモデルではあらゆる操作が最終的にprivilegeなDocker Engineデーモンにより処理されます。Dockerには十分な権限分離システムがなく、あらゆる操作に(イメージのフェッチでさえ)root権限を要求します。Dockerに脆弱性があった場合、コンテナがホストマシンの特権を奪う可能性が危惧されたのは言うまでもなく、実際にCVE-2014-9357のような致命的な脆弱性として現れました。

Dockerがバージョン1.11になってアーキテクチャを大きく変えることになったのは、結局のところ堅牢な権限分離システムを構築できなかったからと言っても過言ではないでしょう。それ以降のバージョンにおけるDocker Engineは直接コンテナの管理をしておらず、containerdを介してrunCを起動する実装に変わりました。モジュールが大きく分断されたことは、プログラムのメンテナンス性を上げるだけではなく、Unixシステムによる権限分離を利用する余地を増やすことに繋がっています。

一方、rktはより抜本的でUnixライクな方法によりこれらの問題に対処しています。

rktにはDocker Engineのような中央型の集中デーモンはなく、クライアントコマンドから直接実行します。故に、既存のスーパーバイザシステムと完全に統合できます。標準のUnixグループ権限を使用して、異なる操作間で特権を分離します。例えば、コンテナイメージのダウンロードと署名検証は特権を持たないユーザーであっても実行できます。仮にrktに脆弱性があったとしても、rktのアプリケーションコンテナは与えられた権限を越えることはできません。もしそれができたとしたら、それはrktではなくカーネルレベルの脆弱性でしょう。

rktを使おう

Dockerへの不満をぶちまけて来ましたが、タイトル通り結論は「rktを使おう!」です。

皆さんもぜひ一度使ってみてください。やみつき間違いなしです。