Docker はコンテナ型仮想化技術を使ってOSレベル仮想化を実現するコンテナ管理ソフトウェアです。類似のコンテナ管理ソフトとしては、Docker の他にも libvirt、 lxc-tools などがありますが、 Docker には以下の大きな特徴があります。
- Infrastructure as Code の思想に基づき、コンテナをコード(Dockerfile) で管理できる
- docker index で、コンテナイメージを手軽に取得、共有できる
Docker は上記のような特徴を持つため、アプリケーションのポータビリティを大きく向上させることができると期待されています。
参考:Naoya Ito 氏 "Dockerアプリケーションのポータビリティを考える"
大変便利な Docker ですが、Docker によるコンテナ管理は、実は数多くの Linux Kernel の機能により実現されています。今回は Docker を支える Linux Kernel の機能についてご紹介します。
調査対象の Docker Version: 0.11
Docker を支える Linux Kernel の機能を、一枚絵にすると、以下のような図になります。
各機能は、大きく分けて、Namespaces、Cgroups、Storage、Networking、Security に大別できます。それぞれについて、概要を簡単に説明します。
Namespaces
ユーザプロセスが動作する空間を分離する Namespace はコンテナ型仮想化を実現する上で、核となる機能です。これらの機能の多くはParallels 社の OpenVZ チームを中心として開発されました。Docker が利用する Namespace には PID、MNT、IPC、UTS、NETの 5種類があります。
PID Namespace(Kernel 2.6.24)
PID(Process ID) Namespace は、プロセスが動作する空間を生成・分離します。あらたに作られたプロセス空間からは、親空間で動作するプロセスが見えなくなります。 "見えなくなる" というのは、kill() システムーコール等、PIDを指定するシステムコールで親空間で動作するプロセスと通信できなくなる、ということです。親空間からは、生成した空間で動作するプロセスは見えます。
MNT Namespace(Kernel 2.4.19)
MNT(Mount) Namespace は、プロセスに見えるファイルシステムのマウント空間を分離する機能です。mount コマンドで見えるファイルシステムのマウント情報を分離します。
IPC Namespace(Kernel 2.6.30)
IPC(Inter-Process Communication) Namespace は System V IPC(メッセージ・キュー、 セマフォ、共有メモリ) と Posix メッセージキュー の空間を分離します。IPC 関連の識別子が、他の空間からは見えなくなります。
UTS Namespace(Kernel 2.6.19)
UTS(Unix Time-sharing System) Namespace は、uname() システムコールで取得できる情報を分離します。Namespace のうち、最も単純で理解しやすいです。
NET Namespace(Kernel 2.6.29)
NET(Network) Namespace は、ネットワークデバイス、IPアドレス、ルーティングテーブル、iptables 情報を分離します。
Docker は、これらの機能により、プロセス間に仕切りを設け、空間を分離することでコンテナを構成します。
上記以外にも、ユーザおよびグループを分離する User Namespace(Kernel 3.8)という機能もあります。将来的に Docker が利用するかもしれません。
Cgroups
Cgroups はプロセス群に割り当てる計算資源(CPU、メモリ、I/O帯域)を管理する機能です。コンテナに割り当てる資源を調整するために使用します。
cpu
指定した通常優先度(Nice -19 ~ 20) プロセスが使用するCPUの利用割合です。
cpuset
指定したプロセスが動作するCPUを制限します。
memory
指定したプロセスが使用するメモリ量を制限します。
device
指定したプロセスが使用できるデバイス(/dev/*)を制限します。
Docker はこれらの機能を使い、コンテナに割り当てる計算資源を制限します。
上記以外にも ブロックI/O 帯域を制限する blkio subsystem や、プロセス群を停止する freeze subsystem 等があります。将来的には Docker でも使われるでしょう。
Storage
Docker は CoW(Copy on Write) と呼ばれる方式でコンテナイメージ間の差分を扱うことで、無駄なくコンテナイメージを管理します。Docker のコンテナイメージを管理する Storage プラグインでは、以下の Kernel の機能を使っています。
Device Mapper
Device Mapper は、ファイルシステム等が発行するブロック I/O とデバイスのマッピング関係を管理します。Docker は Device Mapper の提供する thin-provisioning の機能と、snapshot 機能を活用しています。個別のファイルシステムに依存しないため、幅広い環境で使用することができます。ファイルシステムより下層にあり、ファイル差分を管理できないため、docker diff コマンドの実行速度は Btrfs と比べ遅くなります。
Btrfs
Btrfs は Linux Kernel に取り込まれているファイルシステムの一つで、先進的な機能を持ちます。Docker は Btrfs の subvolume / snapshot 機能を使い、コンテナイメージの差分を管理します。差分はファイルシステム層で管理されるため、docker diff コマンドの実行速度はとても速いです。使用するには、docker のホームディレクトリが btrfs 形式でないといけません。現在 Docker の Btrfs Plugin は、200行ちょっとなのでとても簡単に読めます。
Aufs
Aufs は union ファイルシステムの一種で、ファイルシステム層で差分を管理できる機能を持ちますが、Linux Kernel のメインラインに入っていないため、今後はあまり使われないでしょう。
Device Mapper
Device Mapper は、ファイルシステム等が発行するブロック I/O とデバイスのマッピング関係を管理します。Docker は Device Mapper の提供する thin-provisioning の機能と、snapshot 機能を活用しています。個別のファイルシステムに依存しないため、幅広い環境で使用することができます。ファイルシステムより下層にあり、ファイル差分を管理できないため、docker diff コマンドの実行速度は Btrfs と比べ遅くなります。
Btrfs
Btrfs は Linux Kernel に取り込まれているファイルシステムの一つで、先進的な機能を持ちます。Docker は Btrfs の subvolume / snapshot 機能を使い、コンテナイメージの差分を管理します。差分はファイルシステム層で管理されるため、docker diff コマンドの実行速度はとても速いです。使用するには、docker のホームディレクトリが btrfs 形式でないといけません。現在 Docker の Btrfs Plugin は、200行ちょっとなのでとても簡単に読めます。
Aufs
Aufs は union ファイルシステムの一種で、ファイルシステム層で差分を管理できる機能を持ちますが、Linux Kernel のメインラインに入っていないため、今後はあまり使われないでしょう。
Networking
veth
仮想的なネットワークデバイスのペアを作る機能です。Network Namespace と組み合わせ、ホストとコンテナ間での通信に使います。これも OpenVZ チームが中心に開発したものです。
bridge
仮想的なブリッジを作る機能です。上述の veth と組み合わせ、コンテナ間の通信に使います。QEMU /KVM でおなじみと思います。
iptables
コンテナ間の通信を制御(Drop/Accept)するために使います。
仮想的なネットワークデバイスのペアを作る機能です。Network Namespace と組み合わせ、ホストとコンテナ間での通信に使います。これも OpenVZ チームが中心に開発したものです。
bridge
仮想的なブリッジを作る機能です。上述の veth と組み合わせ、コンテナ間の通信に使います。QEMU /KVM でおなじみと思います。
iptables
コンテナ間の通信を制御(Drop/Accept)するために使います。
Security
Capability
プロセスが持つ特権を細かい粒度で管理する機能です。コンテナ内から、ホストに悪影響を及ぼさないよう制御します。Docker では、例えば、カーネルモジュールのロード、OS時刻の変更などができないよう、デフォルト設定でコンテナ内プロセスの特権を落としています。デフォルト設定:default_template.go
SElinux
強制アクセス制御機能です。Docker ではコンテナ起動時に SElinux MCS ラベルをコンテナに付与し、コンテナ内プロセスの動作をコンテナ内に制限します。
seccomp
プロセスが発行できるシステムコールの種類を制限する機能です。Docker では、--lxc-conf でシステムコールリストファイルを指定してコンテナ内プロセスのシステムコール発行を制限できます。
まとめ
Docker は数多くの Linux Kernel の機能により実現されていることがわかりました。今後、Cgroups、User Namespace、Checkpoint/Restart In Userspace などの実装が進むと思われます。
参考文献
[LWN.net] Namespaces in operation, part 1: namespaces overview
[LWN.net] LSS Secure Linux container
Linux コンテナ入門