📑

Dockerはなぜ速い?軽量仮想化の秘密「カーネル共有とレイヤー構造」を徹底深掘り

に公開

はじめに

Dockerの最大の魅力は「軽量で高速でオーバーヘッドが少ない」仮想環境の提供ですが、
なぜそれが実現できるのか、深く理解していませんでした。

  • 何が軽量なのか?
  • なぜ起動が早いのか?
  • オーバーヘッドがないとは?
    といった疑問が湧いてきたので深掘りしてみようと思います。

今回は、Dockerの高速性の秘密である 「ホストOSのカーネル共有」「レイヤー構造」 に焦点を当てて深掘りしていきます。

対象

  • Dockerを使っているが、どういう動作をしているかまで理解できていない人

従来の仮想化(VM)との違い

一言で言うと 「OSのエミュレーションが不要だから」

従来の仮想マシン(VMwareやVirtualBoxなど)は、物理的なハードウェアの上にハイパーバイザーという仮想化ソフトウェアを置き、その上でゲストOS全体を動作させます。
ゲストOSは独自のカーネルを持ち、起動にはOSのブートプロセス全体が必要となり、その分のリソース(CPU、メモリ)も消費します。これがVMにおけるオーバーヘッドです。

一方、Dockerは異なります。
Dockerコンテナは、ホストOSのカーネルを共有します
コンテナの中にOS全体は含まれておらず、ホストOS上で独立したプロセスとして動作します。

この「OSの起動が不要」という点が、Dockerの高速性の根源です。
PCの電源を入れてWindowsやmacOSが立ち上がるまで時間がかかるように、VMもゲストOSの起動に時間がかかります。
Dockerは、すでに稼働しているホストOSのカーネル上でアプリケーションプロセスを立ち上げるだけなので、このOS起動のオーバーヘッドが丸ごとスキップされます。


プロセス実行による効率性:リソースの直接利用と軽量な分離

Dockerが「プロセス」として実行されることも、高速性にとって重要です。

VMの場合、ゲストOSが仮想化されたハードウェアにアクセスする際、ハイパーバイザーが物理ハードウェアへの操作に変換するエミュレーションが行われます。
これには時間とCPUサイクルがかかります。

対照的に、DockerコンテナはホストOSのカーネルを直接利用するため、物理ハードウェアのリソースにほぼ直接アクセスできます。
エミュレーションの層がないため、性能劣化が非常に小さいです。

また、DockerはLinuxカーネルのNamespacesCgroupsという軽量な機能を使って、コンテナ間の分離とリソース制限を実現します。

  • Namespaces: コンテナごとに独立したプロセス空間、ネットワークインターフェース、ファイルシステムビューなどを提供し、あたかも独立したOSのように見せかけます。
  • Cgroups: 各コンテナが使用できるCPU、メモリ、I/Oなどのリソースを制限し、他のコンテナやホストOSへの影響を防ぎます。

これらの機能は、VMのようにOS全体を仮想化するよりもはるかに効率的で、リソース消費が少ないため、アプリケーションの起動や実行が高速になります。

独立したOS環境を再現する「レイヤー構造」

DockerコンテナはホストOSのカーネルを共有しているにも関わらず、なぜ特定のOSディストリビューション(Ubuntuなど)の挙動やファイルシステムを再現できるのでしょうか?
その秘密は、Dockerイメージの 「レイヤー構造」 にあります。

Dockerイメージは、複数の読み取り専用(Read-only)のレイヤーが積み重ねられた構造をしています。

  1. ベースイメージ: 最下層は、UbuntuやAlpineなどの最小限のOSファイルシステムを含むベースイメージです。これがコンテナの基本的なOS環境を提供します。
  2. 中間レイヤー: Dockerfileの各命令(RUNCOPYなど)が実行されるたびに、新しいレイヤーが作成されます。これには、アプリケーションのインストールや設定変更など、ファイルシステムの「差分」が記録されます。
  3. 書き込み可能なレイヤー: コンテナを起動すると、上記の読み取り専用レイヤーの上に、書き込み可能な新しいレイヤーが追加されます。コンテナ内のファイルの変更はこのレイヤーに記録され、元のイメージレイヤーは変更されません。

すでに存在するイメージがある場合に、pullされずにスキップされていることがコンテナの起動ログを見るとわかります。
これはベースイメージのレイヤーを使っているからです。

Dockerは、Union Filesystemという技術を用いて、これらの読み取り専用レイヤーと書き込み可能なレイヤーをあたかも一つのまとまったファイルシステムであるかのように見せかけます。
さらに、Mount Namespace機能により、各コンテナはホストOSとは独立したファイルシステムのビューを持ちます。

これにより、コンテナ内部から見ると、あたかも/(ルートディレクトリ)から始まる完全なLinuxファイルシステムが存在し、特定のOSディストリビューションのユーザーランド環境が再現されているように見えるのです。

まとめ

Dockerの高速性と軽量性は、主に以下の2つの要素によって実現されています。

  • ホストOSのカーネル共有: OS起動のオーバーヘッドを排除し、アプリケーションを軽量なプロセスとして実行します。
  • レイヤー構造: 独立したファイルシステムと特定のOS環境を効率的に再現します。

これらの技術が、現代のコンテナ技術の基盤であり、Dockerのメリットを最大限に活かすことで、より効率的な開発・運用が可能になります。

Discussion