Dockerの諸問題とRocket登場の経緯

by Taichi Nakashima,

2014年の後半あたりからDocker,Docker Inc.への批判を多く見かけるようになった(もちろんもともと懸念や嫌悪を表明するひとはいた).それを象徴する出来事としてCoreOSチームによる新しいコンテナのRuntimeであるRocketのリリースと,オープンなアプリケーションコンテナの仕様の策定を目指したApp Containerプロジェクトの開始があった.

批判は,セキュリティであったり,ドキュメントされていない謎の仕様やバグだったり,コミュニティの運営だったり,と多方面にわたる.これらは具体的にどういうことなのか?なぜRocketが必要なのか?は具体的に整理されていないと思う.これらは,今後コンテナ技術を使っていく上で,オーケストレーションとかと同じくらい重要な部分だと思うので,ここで一度まとめておきたい.

なお僕自身は,コンテナ技術に初めて触れたのがDockerであり,かつ長い間Dockerに触れているので,Docker派的な思考が強いと思う.またセキュリティに関しても専門ではない.なので,以下の記事はなるべく引用を多くすることを意識した.また,あくまで僕の観測範囲であり,深追いしていないところもある,気になるひとは自分で掘ってみて欲しい.

セキュリティ問題

Dockerを使ったことがあるひとならわかると思うがDockerを使うにはルート権限が必須である.デーモンが常に動いており,それにクライアントがコマンドを発行するアーキテクチャになっているので,Dockerコンテナが動いているホストでは常にルートのプロセスが動き続けることになる.クライアントとデーモンはHTTPでやりとりするため,外部ホストからコマンドを叩くこともできてしまう.

これは怖い.コンテナはカーネルを共有しているので,もし特権昇格の脆弱性であるコンテナがハイジャックされたら,他の全てのコンテナとホストも攻撃されることになる(Container Security: Isolation Heaven or Dependency Hell | Red Hat Security).

実際Docker 1.3.1以前のバージョンでは脆弱性も見つかっている.

docker pullは安全なの?

上記の脆弱性では悪意のあるイメージによる攻撃が指摘されており,攻撃を受けやすいのはdocker pullで外部からイメージを取得/展開するところである.ではここはちゃんと安全になっているのか?答えは「No」で,あまりよろしくないモデルになっており,よく批判されるところでもある.

これはFlynnの開発者が現在のdocker pullの危険性を指摘したブログ記事.要約すると,Dockerは署名されたManifestなるもので公式のDockerイメージの信頼性を確認していると主張しているがそれが全く動作していない,モデルとして危ないということを言っている.具体的には,

  • イメージの検証は,[decompress] -> [tarsum] -> [unpack]処理の後に実行されるが,そもそもここに脆弱性が入り込む余地がある
  • キーはDockerのコードには存在しておらず,イメージをダウンロードする前にCDNからHTTPSで取得するようになっており,これは…

この問題を回避する方法が以下で紹介されている.

ここで紹介されているのはdocker pullを使わない方法.具体的には,信頼できるサイトから,イメージの.tarファイルをダウンロードして,Checksumがあればそれをチエックしたうえで,docker loadでそれを読み込むという方法.

また,DockerfileのFROMでも同様の問題が発生する.ので,ちょっとのタイポで異常なイメージがダウンロード/展開される危険がある.これを回避するためにそもそもindex.docker.ioへのアクセスも禁止してしまおうという方法も紹介されている.具体的には,/etc/hostsを以下のようにしてしまう.

127.0.0.1 index.docker.io

Dockerfile問題

Dockerfileには,なんでこれができないの?やハマりどころが多い.

なんでこれができないの?で一番有名だったのが,DockerfileがDocekerfileという名前しかちゃんと使えなかった問題がある.これは現時点で最新のバージョン1.5で解決された(Docker 1.5の変更点).それ以外にも,INCLUDEによるDockerfileの分割(#735)や,FROMの複数指定(#5726)など,なんでこれできないのだろうということが多々ある.

またDockerfileはハマりどころも多い.一番ハマるのがCacheで,どういうときにCacheされるのか全く分からない.いつCacheが無効になるか分からずにビルドし直しでうおー!となったひとは多いと思う(Gotchas in Writing Dockerfile).他にも環境変数の挙動がおかしなときもある.

これらはバージョンが上がるに連れて解決されていくであろう問題だとは思う.が以下に関しては慎重にならないといけない.

このDockerfileから10年後も同じDockerイメージができるの?

よく言われているように答えは「No」.Dockerはコンテナ内部で起動するデーモン(e.g., PostgresSQLやRedis)は特定のバージョンを使うかを固定できるが,それが依存するライブラリやパッケージに関しては何もできない.Dockerfileを書いたことがある人ならわかると思うが,必ずapt-get updateを書くので.

これに関しては,go getと同じ批判かなと思う.セキュリティ的にも最新のライブラリやパッケージが使われるにこしたことはないと思うし,またどれだけちゃんとテストするか,にもつながると思う(もちろん皆が皆それができる環境ではないからこそこういう批判が登場するのだが)

その一方でソフトウェアのインストールや設定の知識というのは,ChefやPuppet,Ansibleのようなツールに依然として存在しているし,今後もしばらくは必須になる.DockerfileのようなDockerのみでしか使えないものに依存するのは危ない.Packerは当初からその問題を解決しようとしている.詳しくは@mitchellh氏がHNの議論で詳しく語っており,軽く翻訳したので,そちらを参考にしてほしい.

Registry問題

Docker Registryもなかなかの嫌われものである.自分としては便利に使わせてもらっているが,不満はいくつかある.

まず,DockerHub.上述したdocker pullの問題のように,セキュリティ等に関しては完全にDockerHubを信用しないといけない.Automated buildは便利だけど,時にPending地獄に陥りビルドが始まらず何もできなくなるときがある.リリースがDockerHubの安定性に左右されるのはあまり良い状態ではない.Post/Preフックで簡単なスクリプトを動かすこともできない.

では,docker/docker-registryを使って自分で運用するのか.これも実際に運用したひとの辛い話しか聞かない(でかいイメージpushしたら死ぬとか).立ち上げるのは簡単だが,一番大切な認証機構を準備するのに一苦労必要だったりする.

絶対自分で運用したくないから外部のプライベートレジストリサービス,例えばQuay.ioなど,を見ているが,ちゃんと使おうと思うと有料の壁にぶつかる(ただQuay.ioは機能的にも面白いし,CoreOSに買収されてるので期待感はあり,現時点では良い選択かなと思っている).

コンテナイメージの仕様問題

「Dockerがホストを抽象化しDockerさえあればどこでもイメージを起動できる」というのはDockerを使うことの利点として語られることだけど,別の見方をすればDockerがないと何もできないうことになる.“boycott docker”はDockerのことをまるでDockerOSだと批判し,ベンダーロックインに陥る危険性を仮想化技術との比較で語っている.

そういうこともあり,統一的なコンテナイメージの仕様を作ろうという流れは以前からあった(つまり,誰でもコンテナのRumtimeを作れるようにしようと).が,それに対して最近になるまでちゃんとした仕様を作るということをしていなかった.

Docker Inc.の方向性問題

僕はこの問題を追っていて,OSSだけど企業は企業なんだなあということを実感した.Dockerはもはや単にコンテナのRumtimeというコンポーネントでない.Dockerはプラットフォームを目指している.それはDockerCon EU 2014で発表された各ツール群を見れば明らかである(Announcing Docker Machine, Swarm, and Compose for Orchestrating Distributed Apps | Hacker News).これは企業としては当たり前の考え方だし,間違っているとも思わない.コミュニティの意向も間違いなくある.

が,Dockerをコンポーネントとして見ていたCoreOSのようなチームは,何でやねんとはなる.上で紹介したようなセキュリティなど今すぐにでも解決するべき問題がたくさんあるのにも関わらず,またDockerが進もうとしている領域は既に他のツールが解決しているのにも関わらず… これがRocketという新しいRumtimeの登場につながる.

Rocketとは何か

まず,App Containerという標準的なコンテナの仕様が作られ始めた.これにより,コンテナイメージの仕様問題(Dockerによるベンダーロックイン問題)を解決しようとしている.DockerイメージからACIを作る,ACIからDockerイメージを作れるようなツールも作成している.

次にCoreOS/Rocketは,その標準的なコンテナを動かすためのRuntimeである.App ContainerとRocketのレポジトリが分かれているのは,あくまでRocketは実装の1つであることを意図していると思う.DockerとRocketの違いは,ブラウザで言うところのChromeとFirefoxの違いだと思えばよい.

直近のRocketはDockerでも得にヤバいと言われている部分を解決した.

  • ルート権限のデーモンとクライアントのアーキテクチャの廃止(誤解があったので追記.デーモンが動き続けていないというだけで実行そのものにはルート権限が必要です.常に動いているのとコンテナを起動しているときだけ動いているのは大きく違う)
  • 安全なイメージの配布モデルの作成

内部を詳しくは見れていないが,他のCoreOSツールと同様に既にあるテクノロジーをなるべく使うように作られている(例えば内部では,systemd-nspawnを使っている).少し触ってみたが,まだまだ使いやすさとは決して言えないレベル.

まとめ

Dockerの何がすごかったか,コンテナという技術を一般の人にも使いやすくしたところだと思う.現時点でRocketにはDockerほどの使いやすさはない.が,かといってDockerのセキュリティ問題などを無視するわけにもいかない.

今年はKubernetesやMesosといった周辺ツールにひと盛り上がりがありそうだが,ここで書いた諸問題に関してもちゃんと注視しておきたい.

参考