Dockerは、クライアント/サーバーモデルを採用している。コマンドラインのDockerクライアントと、クライアントに対するAPIを提供するデーモン(Dockerサーバー)に分かれている(図4)。これらをDockerエンジンとも呼ぶ。

図4●Dockerのアーキテクチャー
図4●Dockerのアーキテクチャー
[画像のクリックで拡大表示]

 クライアントの機能はシンプルだ。イメージを操作するコマンドと、コンテナーを制御するコマンドに大別される。一つのコマンドからイメージの作成、アップロード、ダウンロード、コンテナーの作成、終了など基本的な操作が一通り可能となっている。

 Dockerサーバーは、クライアントからのコマンドを受け付けると、Linuxのコンテナー機能を利用してコンテナーを生成する。Linuxには、コンテナーに必要なファイルシステム、ネットワーク、プロセスなどを分離するために「namespace」と「cgroup」という仕組みがあり、Dockerはこれらを利用する。

 namespaceを利用すれば、プロセスのID(PID)やネットワークインタフェース名などをコンテナーの内と外で変えられる。例えば、コンテナー内のPIDが「1」のプロセスと、コンテナー外のPIDが「1」が異なるプロセスとして存在できるようになる。

 cgroupは、プロセスのグループに対し、利用するCPU時間やメモリー量に制限を設定できる。

 Dockerでは、あるコンテナーのイメージを基に新しいイメージを作成し、差分を管理可能。これを実現するために、Linuxの「devicemapper」または「aufs」が利用されている。いずれも複数のコンテナーで物理ディスクの領域を共有できるようにする技術だ。

 devicemapperではブロックレベルでのcopy-on-write(CoW)で、aufsではファイルシステムレベルでのCoWで、これを実現する。CoWとは、データのコピー命令時に、直ちにコピーせず、データへの書き換えが発生した段階で実際にコピーする技術である。