Device Mapper ストレージ・ドライバの使用


(以下は古い内容を含むため、確認予定) 正確な内容は、原文を参照ください https://docs.docker.com/storage/storagedriver/device-mapper-driver/


Device Mapper は、Linux 上で多くの高度なボリューム管理技術を支えるカーネル・ベースのフレームワークです。Docker の devicemapper ストレージ・ドライバは、シン・プロビジョニングとスナップショット機能のために、イメージとコンテナ管理にこのフレームワークを活用します。このセクションでは、Device Mapper ストレージ・ドライバを devicemapper と表記します。、カーネルのフレームワークを Device Mapper として言及します。

注釈

devicemapper ストレージ・ドライバを使うには、 RHEL か CentOS Linux 上で商用サポート版 Docker Engine (CS-Engine) を実行 する必要があります。

AUFS の代替

当初の Docker は、Ubuntu と Debian Linux 上で AUFS をストレージのバックエンドに使っていました。Docker が有名になるにつれ、多くの会社が Red Hat Enterprise Linux 上で使いたいと考え始めました。残念ながら、AUFS は Linux カーネル上流のメインラインではないため、RHEL は AUFS を扱いませんでした。

この状況を変えるべく、Red Hat 社の開発者らが AUFS をカーネルのメインラインに入れられるよう取り組みました。しかしながら、新しいストレージ・バックエンドを開発する方が良い考えであると決断したのです。さらに、ストレージのバックエンドには、既に存在していた Device Mapper 技術を基盤としました。

Red Hat 社は Docker 社と協同で新しいドライバの開発に取り組みました。この協調の結果、ストレージ・バックエンドの取り付け・取り外しが可能な(pluggable)Docker エンジンを再設計しました。そして、 devicemapper は Docker がサポートする2つめのストレージ・ドライバとなったのです。

Device Mapper は Linux カーネルのバージョン 2.6.9 以降、メインラインに組み込まれました。これは、RHEL ファミリーの Linux ディストリビューションの中心部です。つまり、 devicemapper ストレージ・ドライバは安定したコードを基盤としており、現実世界における多くのプロダクションへのデプロイをもたらします。また、強力なコミュニティのサポートも得られます。

イメージのレイヤ化と共有

devicemapper ドライバは、全てのイメージとコンテナを自身の仮想デバイスに保管します。これらのデバイスとは、シン・プロビジョニングされ、コピー・オン・ライト可能であり、スナップショットのデバイスです。Device Mapper 技術はファイル・レベルというよりも、ブロック・レベルで動作します。つまり、 devicemapper ストレージ・ドライバのシン・プロビジョニング(thin-provisioning)とコピー・オン・ライト(copy-on-write)処理は、ファイルではなくブロックに対して行います。

注釈

また、スナップショットは シン・デバイス(thin device)仮想デバイス(virtual device) としても参照されます。つまり、 devicemapper ストレージ・ドライバにおいては、どれも同じものを意味します。

devicemapper でイメージを作る高度な手順は、以下の通りです。

  1. devicemapper ストレージ・ドライバはシン・プール(thin pool)を作成します。

ブロック・デバイスかループ用にマウントした薄いファイル(sparse files)上に、このプールを作成します。

  1. 次に ベース・デバイス(base device) を作成します。

ベース・デバイスとは、ファイルシステムのシン・デバイス(thin device)です。どのファイルシステムが使われているかを調べるには、 docker info コマンドを実行し、 Backing filesystem 値を確認します。

  1. それぞれの新しいイメージ(とイメージ・レイヤ)は、このベース・デバイスのスナップショットです。

これらがシン・プロビジョニングされたコピー・オン・ライトなスナップショットです。つまり、これらは初期状態では空っぽですが、データが書き込まれる時だけ容量を使います。

devicemapper では、ここで作成されたイメージのスナップショットが、コンテナ・レイヤになります。イメージと同様に、コンテナのスナップショットも、シン・プロビジョニングされたコピー・オン・ライトなスナップショットです。コンテナのスナップショットに、コンテナ上での全ての変更が保管されます。 devicemapper は、コンテナに対してデータを書き込む時、このプールから必要に応じて領域を割り当てます。

以下のハイレベルな図は、ベース・デバイスのシン・プールと2つのイメージを表します。

ベース・デバイス

細かく図を見ていきますと、スナップショットは全体的に下向きなのが分かるでしょう。各イメージ・レイヤは下にあるレイヤのスナップショットです。各イメージの最も下にあるレイヤは、プール上に存在するベース・デバイスのスナップショットです。このベース・デバイスとは Device Mapper のアーティファクト(artifact;成果物の意味)であり、Docker イメージ・レイヤではありません。

コンテナとは、ここから作成したイメージのスナップショットです。下図は2つのコンテナです。一方は Ubuntu イメージをベースにし、もう一方は Busybox イメージをベースにしています。

2つの Device Mapper 上のコンテナ

devicemapper からの読み込み

devicemapper ストレージ・ドライバが、どのように読み書きしているか見ていきましょう。下図は、サンプル・コンテナが単一のブロック( 0x44f )を読み込むという、ハイレベルな手順です。

Device Mapper 上のコンテナ
  1. アプリケーションがコンテナ内のブロック 0x44f に対して読み込みを要求します。

コンテナは、イメージの薄い(thin)スナップショットであり、データを持っていません。そのかわりに、下層のイメージ層(スタック)にあるイメージのスナップショット上の、どこにデータが保管されているかを示すポインタ(PTR)を持っています。

  1. ストレージ・ドライバは、スナップショットのブロック 0xf33 と関連するイメージ・レイヤ a005... のポインタを探します。

  1. devicemapper はブロック 0xf33 の内容を、イメージのスナップショットからコンテナのメモリ上にコピーします。

  1. ストレージ・ドライバはアプリケーションがリクエストしたデータを返します。

書き込み例

devicemapper ドライバで新しいデータをコンテナに書き込むには、オンデマンドの割り当て(allocate-on-demand) を行います。コピー・オン・ライト処理により、既存のデータを更新します。Device Mapper はブロック・ベースの技術のため、これらの処理をブロック・レベルで行います。

例えば、コンテナ内の大きなファイルに小さな変更を加える時、 devicemapper ストレージ・ドライバはファイル全体コピーをコピーしません。コピーするのは、変更するブロックのみです。各ブロックは 64KB です。

新しいデータの書き込み

コンテナに 56KB の新しいデータを書き込みます。

  1. アプリケーションはコンテナに 56KB の新しいデータの書き込みを要求します。

  1. オンデマンドの割り当て処理により、コンテナのスナップショットに対して、新しい 64KB のブロックが1つ割り当てられます。

書き込み対象が 64KB よりも大きければ、複数の新しいブロックがコンテナに対して割り当てられます。

  1. 新しく割り当てられたブロックにデータを書き込みます。

既存のデータを上書き

既存のデータに対して初めて変更を加える場合、

  1. アプリケーションはコンテナ上にあるデータの変更を要求します。

  1. 更新が必要なブロックに対して、コピー・オン・ライト処理が行われます。

  1. 処理によって新しい空のブロックがコンテナのスナップショットに割り当てられ、そのブロックにデータがコピーされます。

  1. 新しく割り当てられたブロックの中に、変更したデータを書き込みます。

コンテナ内のアプリケーションは、必要に応じた割り当てやコピー・オン・ライト処理を意識しません。しかしながら、アプリケーションの読み書き処理において、待ち時間を増やすでしょう。

Docker で devicemapper を使う設定

複数のディストリビューションにおいて、devicemapper は標準の Docker ストレージ・ドライバです。ディストリビューションには RHEL や派生したものが含まれます。現時点では、以下のディストリビューションがドライバをサポートしています。

  • RHEL/CentOS/Fedora

  • Ubuntu 12.04

  • Ubuntu 14.04

  • Debian

Docker ホストは devicemapper ストレージ・ドライバを、デフォルトでは loop-lvm モードで設定します。このモードは、イメージとコンテナのスナップショットが使うシン・プール(thin pool)を構築するために、スパース・ファイル(sparse file;まばらなファイル)を使う指定です。このモードは、設定に変更を加えることなく、革新的な動きをするように設計されています。しかしながら、プロダクションへのデプロイでは、 loop-lvm モードの下で実行すべきではありません。

どのようなモードで動作しているか確認するには docker info コマンドを使います。

$ sudo docker info
Containers: 0
Images: 0
Storage Driver: devicemapper
 Pool Name: docker-202:2-25220302-pool
 Pool Blocksize: 65.54 kB
 Backing Filesystem: xfs
 [...]
 Data loop file: /var/lib/docker/devicemapper/devicemapper/data
 Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
 Library Version: 1.02.93-RHEL7 (2015-01-28)
 [...]

この実行結果から、Docker ホストは devicemapper ストレージ・ドライバの処理に loop-lvm モードを使っているのが分かります。実際には、 データ・ループ・ファイル (data loop file)メタデータ・ループ・ファイル (Metadata loop file) のファイルが /var/lib/docker/devicemapper/devicemapper 配下にあるのを意味します。これらがループバックにマウントされているパース・ファイルです。

プロダクション用に direct-lvm モードを設定

プロダクションへのデプロイに適した設定は direct-lvm モードです。このモードはシン・プールの作成にブロック・デバイスを使います。以下の手順は、Docker ホストが devicemapper ストレージ・ドライバを direct-lvm 設定で使えるようにします。

注意

既に Docker ホスト上で Docker デーモンを使っている場合は、イメージをどこかに保存する必要があります。そのため、処理を進める前に、それらのイメージを Docker Hub やプライベート Docker Trusted Registry に送信しておきます。

以下の手順は論理データ・ボリュームと、ストレージ・プールの基礎として設定されたシン・プールを使います。ここでは別のブロック・デバイス /dev/xvdf を持っており、処理するための十分な空き容量があると想定しています。デバイスの識別子とボリューム・サイズは皆さんの環境とは異なるかもしれません。手順を進める時は、自分の環境にあわせて適切に置き換えてください。また、手順は Docker デーモンが停止した状態から始めるのを想定しています。

  1. 設定対象の Docker ホストにログインし、Docker デーモンを停止します。

  1. LVM2 パッケージをインストールします。LVM2 パッケージにはユーザー向けのツールが含まれており、簡単に Linux 上で論理ボリュームを管理するものです。

  1. 物理ボリュームにブロック・デバイス /dev/xvdf を作成します。

$ pvcreate /dev/xvdf
  1. docker ボリューム・グループを作成します。

$ vgcreate docker /dev/xvdf
  1. thinpool という名前のシン・プール(thin pool)を作成します。

この例では、 docker ボリューム・グループの論理データ(data logical)は 95% の大きさとします。残りの容量は、データもしくはメタデータによって空き容量が少なくなった時の一時的な退避用に使います。

$ lvcreate --wipesignatures y -n thinpool docker -l 95%VG
$ lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
  1. プールをシン・プールに変換します。

$ lvconvert -y --zero n -c 512K --thinpool docker/thinpool --poolmetadata docker/thinpoolmeta
  1. lvm プロフィールを経由してシン・プールを自動拡張するよう設定します。

$ vi /etc/lvm/profile/docker-thinpool.profile
  1. thin_pool_autoextend_threshold 値を指定します。

ここで指定する値は、先ほどの lvm 領域がどの程度まで到達したら、領域をどこまで自動拡張するかをパーセントで指定します(100 = 無効化です)。

thin_pool_autoextend_threshold = 80
  1. シン・プールの自動拡張が発生するタイミングを指定します。

シン・プールの領域を増やす空き容量のタイミングをパーセントで指定します(100 = 無効化です)。

thin_pool_autoextend_percent = 20
  1. 確認をします。 docker-thinpool.profile は次のように表示されます。

/etc/lvm/profile/docker-thinpool.profile ファイルの例:

activation {
    thin_pool_autoextend_threshold=80
    thin_pool_autoextend_percent=20
}
  1. 新しい lvm プロフィールを適用します。

$ lvchange --metadataprofile docker-thinpool docker/thinpool
  1. lv (論理ボリューム)をモニタしているのを確認します。

$ lvs -o+seg_monitor
  1. Docker Engine を起動していた場合は、グラフ・ドライバを直接削除します。

Docker インストール時のイメージとコンテナからグラフ・ドライバを削除します。

$ rm -rf /var/lib/docker/*
  1. Engine デーモンが devicemapper オプションを使うように設定します。

設定には2つの方法があります。デーモンの起動時にオプションを指定するには、次のようにします。

--storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt dm.use_deferred_removal=true

あるいは daemon.json 設定ファイルで起動時に指定も可能です。例:

{
        "storage-driver": "devicemapper",
        "storage-opts": [
                "dm.thinpooldev=/dev/mapper/docker-thinpool",
                "dm.use_deferred_removal=true"
        ]
}
  1. systemd を使っているのであれば、unit あるいはドロップイン・ファイルを経由してデーモン設定を変更するため、変更を読み取るため systemd を再読み込みします。

$ systemctl daemon-reload
  1. Docker Engine デーモンを起動します。

$ systemctl start docker

Docker Engine デーモンを起動したら、シン・プールとボリューム・グループの空き容量を確認します。ボリューム・グループは自動拡張しますので、容量を使い尽くす可能性があります。論理ボリュームを監視するには、オプションを指定せず lvs を使うか、 lvs -a でデータとメタデータの大きさを確認します。ボリューム・グループの空き容量を確認するには vgs コマンドを使います。

先ほど設定したシン・プールの閾値を越えたかどうかを確認するには、次のようにログを表示します。

journalctl -fu dm-event.service

シン・プールで問題を繰り返す場合は、 dm.min_free_spaces オプションで Engine の挙動を調整できます。この値は最小値に近づいた時、警告を出して操作させなくします。詳しい情報は ストレージ・ドライバごとのオプション をご覧ください。

ホスト上の devicemapper 構造の例

lsblk コマンドを使えば、先ほど作成したデバイス・ファイルと、その上に devicemapper ストレージ・ドライバによって作られた pool (プール)を確認できます。

$ sudo lsblk
NAME                       MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                       202:0    0    8G  0 disk
└─xvda1                    202:1    0    8G  0 part /
xvdf                       202:80   0   10G  0 disk
├─vg--docker-data          253:0    0   90G  0 lvm
│ └─docker-202:1-1032-pool 253:2    0   10G  0 dm
└─vg--docker-metadata      253:1    0    4G  0 lvm
  └─docker-202:1-1032-pool 253:2    0   10G  0 dm

下図は、先ほどの例で扱ったイメージの更新を、 lsblk コマンドの詳細とあわせて表しています。

ディスク構造上のイメージ

この図では、プールは Docker-202:1-1032-pool と名付けられ、先ほど作成した datametadata デバイスにわたっています。この devicemapper のプール名は、次のような形式です。

Docker-MAJ:MIN-INO-pool

MAJNININO は、デバイスのメジャー番号、マイナー番号、i ノード番号です。

Device Mapper はブロック・レベルで処理を行うため、イメージ・レイヤとコンテナ間の差分を見るのは、少し大変です。しかしながら、2つの鍵となるディレクトリがあります。 /var/lib/docker/devicemapper/mnt ディレクトリには、イメージとコンテナのマウント・ポイントがあります。 /var/lib/docker/devicemapper/metadata ディレクトリには、それぞれのイメージとコンテナのスナップショットを格納する1つのファイルがあります。このファイルには、各スナップショットのメタデータが JSON 形式で含みます。

実行中デバイスの容量を増やす

実行中のシン・プール・デバイスのプール容量を増加できます。データの論理ボリュームが一杯になる時やボリューム・グループの容量が一杯になる時に便利です。

loop-lvm 用の設定

このシナリオでは、シン・プールは loop-lvm モードの設定とします。 docker info を使うと現在の設定詳細を表示します。

$ sudo docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 2
Server Version: 1.11.0-rc2
Storage Driver: devicemapper
 Pool Name: docker-8:1-123141-pool
 Pool Blocksize: 65.54 kB
 Base Device Size: 10.74 GB
 Backing Filesystem: ext4
 Data file: /dev/loop0
 Metadata file: /dev/loop1
 Data Space Used: 1.202 GB
 Data Space Total: 107.4 GB
 Data Space Available: 4.506 GB
 Metadata Space Used: 1.729 MB
 Metadata Space Total: 2.147 GB
 Metadata Space Available: 2.146 GB
 Udev Sync Supported: true
 Deferred Removal Enabled: false
 Deferred Deletion Enabled: false
 Deferred Deleted Device Count: 0
 Data loop file: /var/lib/docker/devicemapper/devicemapper/data
 WARNING: Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.
 Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
 Library Version: 1.02.90 (2014-09-01)
Logging Driver: json-file
[...]

Data Space (データ領域)の値は合計 100GB です。この例ではプールを 200GB に拡張します。

  1. デバイスの容量一覧を表示します。

$ sudo ls -lh /var/lib/docker/devicemapper/devicemapper/
total 1175492
-rw------- 1 root root 100G Mar 30 05:22 data
-rw------- 1 root root 2.0G Mar 31 11:17 metadata
  1. data ファイルを metadata ファイルの容量(約 200GB)に切り出します(truncate)。

$ sudo truncate -s 214748364800 /var/lib/docker/devicemapper/devicemapper/data
  1. 変更を確認します。

$ sudo ls -lh /var/lib/docker/devicemapper/devicemapper/
total 1.2G
-rw------- 1 root root 200G Apr 14 08:47 data
-rw------- 1 root root 2.0G Apr 19 13:27 metadata
  1. ループ・デバイスをのデータを再読み込みします。

$ sudo blockdev --getsize64 /dev/loop0
107374182400
$ sudo losetup -c /dev/loop0
$ sudo blockdev --getsize64 /dev/loop0
214748364800
  1. devicemapper シン・プールを再読み込みします。

  1. まずプール名を取得します。

$ sudo dmsetup status | grep pool
docker-8:1-123141-pool: 0 209715200 thin-pool 91
422/524288 18338/1638400 - rw discard_passdown queue_if_no_space -

名前はコロンの前の文字列です。

  1. そして、デバイス・マッパー・テーブルをダンプします。

$ sudo dmsetup table docker-8:1-123141-pool
0 209715200 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
  1. シン・プールの現在の実合計セクタを計算します。

テーブル情報の2つめの数値(例: セクタ数)を変更するため、ディスク内で新しい 512 バイトのセクタを反映します。例えば、新しいプール容量が 200GB であれば、2つめの数値は 419430400 に変わります。

  1. 新しいセクタ番号でシン・プールを再読み込みします。

$ sudo dmsetup suspend docker-8:1-123141-pool \
    && sudo dmsetup reload docker-8:1-123141-pool --table '0 419430400 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing' \
    && sudo dmsetup resume docker-8:1-123141-pool

device_tool

Docker プロジェクトの contrib ディレクトリにあるのは、ディストリビューションのコア(中心)ではありません。これらのツールは多くの場面で役立ちますが、古いものがあるかもしれません。ディレクトリ内にある device_tool.go で loop-lvm シン・プールの容量変更も可能です。

ツールを使うためには、まずコンパイルします。それからプール容量を次のように変更します:

$ ./device_tool resize 200GB

direct-lvm モード用の設定

この例では direct-lvm 設定を使って実行中デバイスの容量を拡張します。例では /dev/sdh1 ディスク・パーティションを使っているものと想定します。

  1. ボリューム・グループ(VG) vg-docker を拡張します。

$ sudo vgextend vg-docker /dev/sdh1
Volume group "vg-docker" successfully extended

皆さんは別のボリューム名を使っているかもしれません。

  1. data 論理ボリューム(LV) vg-docker/data を拡張します。

$ sudo lvextend  -l+100%FREE -n vg-docker/data
Extending logical volume data to 200 GiB
Logical volume data successfully resized
  1. devicemapper シン・プールを再読み込みします。

  1. プール名を取得します。

$ sudo dmsetup status | grep pool
docker-253:17-1835016-pool: 0 96460800 thin-pool 51593 6270/1048576 701943/753600 - rw no_discard_passdown queue_if_no_space

名前はコロン前の文字列です。

  1. デバイス・マッパー・テーブルをダンプします。

$ sudo dmsetup table docker-253:17-1835016-pool
0 96460800 thin-pool 252:0 252:1 128 32768 1 skip_block_zeroing
  1. シン・プールの現在の実合計セクタを計算します。 blockdev を使って data 論理ボリュームの実サイズを取得できます。

テーブル情報の2つめの数値(例: ディスク終了セクタ)を変更するため、ディスク内で新しい 512 バイトのセクタを反映します。例えば、新しい data 論理ボリューム容量が 264132100096 バイト であれば、2つめの数値は 515883008 に変わります。

$ sudo blockdev --getsize64 /dev/vg-docker/data
264132100096
  1. それから新しいセクタ番号でシン・プールを再読み込みします。

$ sudo dmsetup suspend docker-253:17-1835016-pool \
    && sudo dmsetup reload docker-253:17-1835016-pool --table  '0 515883008 thin-pool 252:0 252:1 128 32768 1 skip_block_zeroing' \
    && sudo dmsetup resume docker-253:17-1835016-pool

Device Mapper と Docker 性能

オンデマンドの割り当て(allocate-on-demand)とコピー・オン・ライト(copy-on-write)処理が、コンテナ全体の性能に対して影響があるのを理解するのは重要です。

オンデマンドの割り当てが性能に与える影響

devicemapper ストレージ・ドライバは、オンデマンドの割り当て処理時、コンテナに対して新しいブロックを割り当てます。この処理が意味するのは、コンテナの中でアプリケーションが何か書き込みをするごとに、プールから1つまたは複数の空ブロックを探し、コンテナの中に割り当てます。

全てのブロックは 64KB です。64KB より小さな書き込みの場合でも、64KB のブロックが1つ割り当てられます。これがコンテナの性能に影響を与えます。特にコンテナ内で多数の小さなファイルを書き込む場合に影響があるでしょう。しかしながら、一度ブロックがコンテナに対して割り当てられたら、以降の読み込みは対象のブロックを直接処理できます。

コピー・オン・ライトが性能に与える影響

コンテナ内のデータを初めて更新する度に、毎回 devicemapper ストレージ・ドライバがコピー・オン・ライト処理を行います。このコピーとは、イメージのスナップショット上のデータを、コンテナのスナップショットにコピーするものです。この処理が、コンテナの性能に対して留意すべき影響を与えます。

コピー・オン・ライト処理は 64KB 単位で行います。そのため、1GB のファイルのうち 32KB を更新する場合は、コンテナのスナップショット内にある 64KB のブロックをコピーします。これはファイル・レベルのコピー・オン・ライト処理に比べて、著しい性能向上をもたらします。ファイル・レベルであれば、コンテナ・レイヤに含まれる 1GB のファイル全体をコピーする必要があるからです。

しかしながら、現実的には、コンテナが多くの小さなブロック(64KB以下)に書き込みをするのであれば、 devicemapper は AUFS を使うよりも性能が劣ります。

Device Mapper の性能に対するその他の考慮

devicemapper ストレージ・ドライバの性能に対して、他にもいくつかの影響を与える要素があります。

  • 動作モード :Docker が devicemapper ストレージ・ドライバを使用する時、デフォルトのモードは loop-lvm です。このモードはスパース・ファイル(space files;薄いファイル)を使うため、性能を損ないます。そのため、loop-lvmプロダクションへのデプロイに推奨されていません 。プロダクション環境で推奨されるモードは direct-lvm です。これはストレージ・ドライバが直接 raw ブロック・デバイスに書き込みます。

  • 高速なストレージ :ベストな性能を出すためには、 データ・ファイルメタデータ・ファイル を、 SSD のような高速なストレージ上に配置すべきです。あるいは、 SAN や NAS アレイといった、ダイレクト・アタッチ・ストレージでも同様でしょう。

  • メモリ使用量 : Docker ストレージ・ドライバの中で、メモリ使用効率が最も悪いのが devicemapper です。同じコンテナのコピーをn個起動する時、n個のファイルをメモリ上にコピーします。これは、Docker ホスト上のメモリに対して影響があります。そのため、 PaaS や他の高密度な用途には、devicemapper ストレージ・ドライバがベストな選択肢とは言えません。

最後に1点、データ・ボリュームは最上かつ最も予測可能な性能を提供します。これは、ストレージ・ドライバを迂回し、シン・プロビジョニングやコピー・オン・ライト処理を行わないためです。そのため、データ・ボリューム上で重たい書き込みを行うのに適しています。

関連情報

参考

Docker and the Device Mapper storage driver

https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/