だいぶ前からDocker(Linuxコンテナ)のパフォーマンスについて、速いことは速いだろうけどどの程度速いのか、もし遅いことがあるなら何がパフォーマンスにとって重要なのか(AUFSが遅いとかそういうの)が気になっていたので、今回は
で紹介されていた Docker のパフォーマンス検証に関する IBM の Research Report を読んだ。Report の内容をベースに、Docker のパフォーマンスの勘所などをまとめてみた。 Report のタイトルは An Updated Performance Comparison of Virtual Machines and Linux Containers 。 GitHub にベンチマークコードと実験データが置いてあってちゃんとしてる。
前提
まず、VMとコンテナの歴史を振り返るのに知らぬはエンジニアの恥。今さら聞けない【コンテナ/仮想化技術】11選 - paiza開発日誌 も併せて読んでおくとよさそう。
次に、Etsukata blog: Docker を支える Linux Kernel の機能 (概要編) と Dockerを支える技術 が Docker が使ってるカーネル周りの技術についてわかりやすいので、絶対読みたい。
特に、Docker のドライバ周りについて、exec driver、storage driver、Host Networking、Volume について軽く見ておくと良さそう。
exec-driver: Docker 0.9: introducing execution drivers and libcontainer | Docker Blog
- Docker は LXC のラッパーとか言われてたけど、今は Linux Containers API を直接叩く Go ライブラリが使われてる。(LXC やその他の Linux コンテナのフロントエンドも選べる)
storage-driver: Docker 0.7 runs on all Linux distributions – and 6 other major features | Docker Blog
- Docker のイメージ差分管理機能は従来 AUFS のみが使われていて、AUFS は Linux カーネルのメインラインの機能ではないので、カーネル標準の Device Mapper (dm-thin)もドライバにできるようになった。 Btrfs も使える。
- Comprehensive Overview of Storage Scalability in Docker | Red Hat Developer Blog についても参考になる。
Host Networking: Advanced networking - Docker Documentation
- Docker はコンテナ内のポートをホスト側の任意のポート番号をもつポートとして公開できる。つまり、NAPTするわけだけど、NAPTのオーバヘッドを回避するために、コンテナではなくホストのネットワークスタックを使うようにできる Host Networking 機能がある。
- 必ずしも、NAPTオーバヘッド回避のためだけではなく、ホストと同じインタフェースみえててほしいとかもある。
Volume: Managing data in containers - Docker Documentation
- コンテナ間およびホスト間のデータ共有のために、差分ファイルシステム(AUFSなど)をバイパスする特別なディレクトリ。おそらくコンテナごとにデータを格納するものではなく、Docker グローバルで参照できるディレクトリ。
- docker commit data container with VOLUME · Issue #6999 · docker/docker · GitHub
- docker - Data Volume と Data Volume Container - Qiita
概要と考察
Report 自体は、クラウド(IaaS)事業者視点で、コンテナ(Docker), VM(KVM), Native Linux(仮想化してない普通のLinux) の3者の性能を比較してる。 性能評価の観点は、プロセッサ(FLOPS)、メモリ帯域幅、メモリIOPS、ネットワーク帯域幅、ネットワークレイテンシ、ブロックデバイスの帯域幅、ブロックデバイスのIOPSなどとなっている。 LINPACK、 netperf や fio などを用いた OS のベンチマークだけでなく、実用的なアプリケーションとして MySQL と Redis についてもベンチマークされている。 自分の場合は、EC2 インスタンスまたはオンプレの Xen Domain U で Docker コンテナを動かすことになるだろうから、VM と コンテナの比較よりは、Native Linux とコンテナの比較に興味があった。
レポートの3章のグラフをみるとわかるが、結論から言うと、Docker のオーバヘッドをなるべく削減する構成にすれば、各評価において Docker は Native Linux と同等かやや劣る程度で、実用上それほど問題になることはなさそうだ。 CPU、メモリ周りとネットワークとブロックデバイスの帯域幅については同等である。 CPU/メモリ集約なアプリケーションとか動画配信サーバみたいな帯域幅集約なアプリケーションなら気にすることは特に何もない。
逆に、 MySQL と Redis のようなストレージまたはネットワークのIOPSが支配的なアプリケーションではパフォーマンスが劣化する。 原因は AUFS と NAPT で、NAPT のポート変換オーバヘッドと I/O 要求が AUFS の各ファイルシステム層を通過するオーバヘッドがある。 ただし、Docker の Host Networking とか Volume 機能を使って、前述のオーバヘッドをかなりの部分まで削減することができる。(それでも、MySQLについてはNativeと比べて多少性能が落ちる。レイテンシの僅かな差がスループットに影響を与えている。)ただしこれはコンテナのポータビリティとパフォーマンスのトレードオフになる。 例えば、NAPT を使わなくすると、コンテナが公開するポートとホストのポートがコンフリクトすることもあり、Dockerコンテナがどこでも動くというわけではなくなる。また、Volume 機能を使うと、Docker イメージにデータを書き出すことができないため、コンテナをデータごと他所に持って行きづらくなってしまう。
CPU、メモリ周りは通常用途にはそんなに気にするポイントなかったので、ブロックI/O or ネットワークI/O集約なアプリケーション(MySQL とか HAProxy)以外は自分が触ってるような環境の場合本番投入しても問題なさそうな印象を受けた。 MySQL や Redis についてはステートフルなので、そもそもインスタンスの増減や引っ越しがステートレスサーバほど気軽にはできないので、多少人間的なオペレーションが入ってもよい。 つまり、それほどポータビリティが重要なわけではない。実行環境はDockerなのでそのままで、データだけは Volume ディレクトリの内容をホストに書き出して別途コピーしておけばよい。 また、statefull なアプリケーションについては、同じアプリケーションを同じホストで動かさない運用にしておけば、ポート番号はウェルノウンポート決め打ちぐらいでよさそう。
スライド
細かい実験条件などはより詳しい内容についてはスライドまたはReport 本文を参照。
感想
スライドの最後にも書いてるけど、コンテナは隔離されたプロセスぐらいのイメージなので、VMに比べて速いに決まってるし、Native Linuxと遜色ないのもまぁそうかという感じ。AUFS 遅いというのもまぁそうかという感じで、Device Mapper とか Btrfs との比較が気になるところ。AUFS以外の storage driver についてComprehensive Overview of Storage Scalability in Docker | Red Hat Developer Blog が参考になる。(大量のコンテナの作成と削除を以下に速くできるかが指標となっているので、やっていることはだいぶ違う)
関係ないけど、Docker の本番投入の問題はパフォーマンス云々以上に、既存のワークフローにいかに組み込むかと問題が発生したときのデバッグまたは障害対応であるというのがここ半年くらいの認識になっている。
気になる参考文献
今回の Report は参考文献が豊富で、いくつか気になったので紹介しておく。
https://www.gronkulator.com/overhead.htmlhttps://www.gronkulator.com/overhead.html
Software Defined Boden: KVM and Docker LXC Benchmarking with OpenStack
はてなでは、Docker 好きな人とか、論文読んで知見を共有したり本番投入したい人も募集しています↓↓↓
採用情報 - 株式会社はてな