イメージ、コンテナ、ストレージ・ドライバの理解

ストレージ・ドライバを効率的に使うには、Docker がどのようにイメージを構築・保管するかの理解が欠かせません。そして、これらのイメージがコンテナでどのように使われているかの理解が必要です。最後に、イメージとコンテナの両方を操作するための技術に対する、簡単な紹介をします。

イメージとレイヤ

Docker イメージは読み込み専用(read-only)レイヤのセットです。それぞれのレイヤが層(スタック)として積み重なり、1つに統合された形に見えます。この1番めの層を ベース・イメージ (base image) と呼び、他の全てのレイヤは、このベース・イメージのレイヤ上に積み重なります。次の図は、 Ubuntu 15.04 イメージが4つのイメージ・レイヤを組みあわせて構成されているのが分かります。

イメージ層

Docker ストレージ・ドライバは、これらレイヤを積み重ねて単一に見えるようにする役割があります。

コンテナ内部に変更を加えた時を考えます。例えば、Ubuntu 15.04 イメージ上に新しくファイルを追加したら、下にあるイメージ層の上に、新しいレイヤを追加します。この変更は、新しく追加したファイルを含む新しいレイヤを作成します。各イメージ・レイヤは自身の UUID(universal unique identifier)を持っており、下の方にあるイメージの上に、連続したイメージ・レイヤを構築します。

コンテナ(ストレージの内容を含みます)は Docker イメージと薄い書き込み可能なレイヤとを連結したものです。この書き込み可能なレイヤは一番上にあり、 コンテナ・レイヤ(container layer) と呼ばれます。以下の図は ubuntu 15.04 イメージの実行状態です。

コンテナ・レイヤとイメージ

連想ストレージ

Docker 1.10 は、新しい連想(コンテント・アドレッサブル;content adressable)ストレージ・モデルを導入しました。これはイメージとレイヤをディスクで扱うための、全く新しい手法です。従来のイメージとレイヤのデータは、ランダムに生成した UUID を使って保管・参照していました。新しいモデルでは、これを安全な コンテント・ハッシュ(content hash) に置き換えます。

新しいモデルはセキュリティを改善します。ID の重複を防ぐ機能を持っており、pull ・ push ・ load ・ save 操作を実施後のデータ保証を完全なものとします。また、同時に構築していなくても、多くイメージが各レイヤを自由に共有可能にもなりました。

次の図は、従来バージョンの図を更新したものです。Docker 1.10 で実装された変更をハイライトしています。

コンテナ・レイヤとイメージ

こちらにある通り、まだコンテナ ID がランダムな UUID であるのに対して、全てのイメージ・レイヤの ID は暗号化ハッシュです。

新しいモデルに関しては、いくつかの注意点があります。

  1. 既存イメージの移行
  2. イメージとレイヤのファイルシステム構造

既存イメージとは、以前のバージョンの Docker で作成、あるいは取得したものです。これらは新しいモデルで使う前に、変換が必要です。以降時には、新しい安全なチェックサムを計算します。この計算は更新した Docker デーモンを初回起動時、自動的に行われます。移行が終わったら、全てのイメージとタグが新しい安全な ID に更新されます。

移行は自動的かつ透過的に行われますが、多くの計算を必要とします。つまり、イメージ・データが大量にあれば、時間がかかることを意味します。移行している間、Docker デーモンは他のリクエストに応答しません。

新しいイメージへの移行を、Docker デーモンをアップグレードする前に行えるツールがあります。つまり、移行に時間をかけないので、停止時間の発生を避けられます。また、既存のイメージを手動で移行できますので、最新バージョンの Docker が既に動いている環境への移行も可能です。

Docker 社が提供している移行ツールは、コンテナとして実行できます。 https://github.com/docker/v1.10-migrator/releases からダウンロードできます。

「migrator」イメージの実行中は、Docker ホストのデータ・ディレクトリをコンテナに対して公開する必要があります。Docker データを置く場所がデフォルトであれば、コマンドラインでコンテナを実行するには、次のようにします。

$ sudo docker run --rm -v /var/lib/docker:/var/lib/docker docker/v1.10-migrator

devicemapper ストレージ・ドライバを使っている場合は、 --privileged オプションを使ってコンテナがストレージ・デバイスにアクセスできるようにする必要があります。

移行例

以下の例は、 Docker デーモンのホスト・バージョンが 1.9.1 で、 AUFS ストレージ・ドライバを使っている環境を移行します。Docker ホストは t2.micro* AWS EC2 インスタンス上で動いており、1 vCPU 、1GB メモリ、8GB の SSD EBS ボリュームを持っています。Docker のデータ・ディレクトリ( /var/lib/docker )は 2GB の容量を使っています。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
jenkins             latest              285c9f0f9d3d        17 hours ago        708.5 MB
mysql               latest              d39c3fa09ced        8 days ago          360.3 MB
mongo               latest              a74137af4532        13 days ago         317.4 MB
postgres            latest              9aae83d4127f        13 days ago         270.7 MB
redis               latest              8bccd73928d9        2 weeks ago         151.3 MB
centos              latest              c8a648134623        4 weeks ago         196.6 MB
ubuntu              15.04               c8be1ac8145a        7 weeks ago         131.3 MB

$ sudo du -hs /var/lib/docker
2.0G    /var/lib/docker

$ time docker run --rm -v /var/lib/docker:/var/lib/docker docker/v1.10-migrator
Unable to find image 'docker/v1.10-migrator:latest' locally
latest: Pulling from docker/v1.10-migrator
ed1f33c5883d: Pull complete
b3ca410aa2c1: Pull complete
2b9c6ed9099e: Pull complete
dce7e318b173: Pull complete
Digest: sha256:bd2b245d5d22dd94ec4a8417a9b81bb5e90b171031c6e216484db3fe300c2097
Status: Downloaded newer image for docker/v1.10-migrator:latest
time="2016-01-27T12:31:06Z" level=debug msg="Assembling tar data for 01e70da302a553ba13485ad020a0d77dbb47575a31c4f48221137bb08f45878d from /var/lib/docker/aufs/diff/01e70da302a553ba13485ad020a0d77dbb47575a31c4f48221137bb08f45878d"
time="2016-01-27T12:31:06Z" level=debug msg="Assembling tar data for 07ac220aeeef9febf1ac16a9d1a4eff7ef3c8cbf5ed0be6b6f4c35952ed7920d from /var/lib/docker/aufs/diff/07ac220aeeef9febf1ac16a9d1a4eff7ef3c8cbf5ed0be6b6f4c35952ed7920d"
<snip>
time="2016-01-27T12:32:00Z" level=debug msg="layer dbacfa057b30b1feaf15937c28bd8ca0d6c634fc311ccc35bd8d56d017595d5b took 10.80 seconds"

real    0m59.583s
user    0m0.046s
sys     0m0.008s

Unix の time コマンドを docker run コマンドより前に付け、処理時間を計測します。表示されているように、2GB の容量を消費している7つのディスク・イメージの移行に、おおよそ1分かかっています。しかし、これには docker/v1.10-migrator イメージの取得(約3.5秒)も含みます。同じ処理を m4.10xlarge EC2 インスタンス、40 VCPU 、160GB のメモリ、8GB の provisioned IOPS EBS ボリュームであれば、次のような結果になります。

real    0m9.871s
user    0m0.094s
sys     0m0.021s

以上の結果から、処理時間は移行をするマシンのハードウェア性能に影響を受けることが分かります。

コンテナとレイヤ

それぞれのコンテナは、自分自身で書き込み可能なレイヤを持ちますので、全てのデータは対象のコンテナレイヤに保管します。つまり、複数のコンテナが根底にあるイメージを共有アクセスすることができ、それぞれのコンテナ自身がデータをも管理できるのを意味します。次の図は複数のコンテナが同じ Ubuntu 15.04 イメージを共有しています。

レイヤの共有

ストレージ・ドライバは、イメージ・レイヤと書き込み可能なコンテナ・レイヤの両方を有効化・管理する責任があります。ストレージ・ドライバは様々な方法で処理をします。Docker イメージとコンテナ管理という2つの重要な技術の裏側にあるのは、積み上げ可能なイメージ・レイヤとコピー・オン・ライト(CoW)です。

コピー・オン・ライト方式

共有とはリソース最適化のための良い手法です。人々はこれを日常生活通で無意識に行っています。例えば双子の Jane と Joseph が代数学のクラスを受ける時、回数や先生が違っても、同じ教科書を相互に共有できます。ある日、Jane が本のページ11にある宿題を片付けようとしています。その時 Jane はページ11をコピーし、宿題を終えたら、そのコピーを提出します。Jane はページ 11 のコピーに対する変更を加えただけであり、オリジナルの教科書には手を加えていません。

コピー・オン・ライト(copy-on-write、cow)とは、共有とコピーのストラテジ(訳者注:方針、戦略の意味、ここでは方式と訳します)に似ています。このストラテジは、システム・プロセスが自分自身でデータのコピーを持つより、同一インスタンス上にあるデータ共有を必要とします。書き込む必要があるプロセスのみが、データのコピーにアクセスできます。その他のプロセスは、オリジナルのデータを使い続けられます。

Docker はコピー・オン・ライト技術をイメージとコンテナの両方に使います。この CoW 方式はイメージのディスク使用量とコンテナ実行時のパフォーマンスの両方を最適化します。次のセクションでは、イメージとコンテナの共有とコピーにおいて、コピー・オン・ライトがどのように動作してるのかを見てきます。

共有を促進する小さなイメージ

このセクションではイメージ・レイヤとコピー・オン・ライト技術(copy-on-write)を見ていきます。全てのイメージとコンテナ・レイヤは Docker ホスト上の ローカル・ストレージ領域 に存在し、ストレージ・ドライバによって管理されます。Linux をベースとする Docker ホストでは、通常は /var/lib/docker/ 以下です。

イメージ取得・送信する docker pulldocker push 命令の実行時、Docker クライアントはイメージ・レイヤについて報告します。以下のコマンドは、 Docker Hub から ubuntu:15.04 Docker イメージを取得(pull)しています。

$ docker pull ubuntu:15.04
15.04: Pulling from library/ubuntu
1ba8ac955b97: Pull complete
f157c4e5ede7: Pull complete
0b7e98f84c4c: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
Status: Downloaded newer image for ubuntu:15.04

この出力から、このコマンドが実際には4つのイメージ・レイヤを取得したのが分かります。上記のそれぞれの行が、イメージとその UUID か暗号化ハッシュです。これら4つのレイヤの組みあわせにより、 ubuntu:15.04 Docker イメージを作り上げています。

これらの各レイヤは、Docker ホスト上のローカル・ストレージ領域に保管します。

Docker バージョン 1.10 未満までは、各レイヤをイメージ・レイヤ ID と同じ名前のディレクトリに格納していました。しかし、Docker バージョン 1.10 移行では、イメージを取得してもこのようになりません。例えば、Docker Engine バージョン 1.9.1 が動いているホスト上で、 Docker Hub からイメージをダウンロードするコマンドを実行した結果です。

$  docker pull ubuntu:15.04
15.04: Pulling from library/ubuntu
47984b517ca9: Pull complete
df6e891a3ea9: Pull complete
e65155041eed: Pull complete
c8be1ac8145a: Pull complete
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
Status: Downloaded newer image for ubuntu:15.04

$ ls /var/lib/docker/aufs/layers
47984b517ca9ca0312aced5c9698753ffa964c2015f2a5f18e5efa9848cf30e2
c8be1ac8145a6e59a55667f573883749ad66eaeef92b4df17e5ea1260e2d7356
df6e891a3ea9cdce2a388a2cf1b1711629557454fd120abd5be6d32329a0e0ac
e65155041eed7ec58dea78d90286048055ca75d41ea893c7246e794389ecf203

4つのディレクトリが、イメージをダウンロードしたレイヤの ID と一致しているのが分かるでしょう。これと同じ処理を Docker Engine バージョン 1.10 上で行いましょう。

$ docker pull ubuntu:15.04
15.04: Pulling from library/ubuntu
1ba8ac955b97: Pull complete
f157c4e5ede7: Pull complete
0b7e98f84c4c: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
Status: Downloaded newer image for ubuntu:15.04

$ ls /var/lib/docker/aufs/layers/
1d6674ff835b10f76e354806e16b950f91a191d3b471236609ab13a930275e24
5dbb0cbe0148cf447b9464a358c1587be586058d9a4c9ce079320265e2bb94e7
bef7199f2ed8e86fa4ada1309cfad3089e0542fec8894690529e4c04a7ca2d73
ebf814eccfe98f2704660ca1d844e4348db3b5ccc637eb905d4818fbfb00a06a

先ほどの結果とは異なり、4つのディレクトリは取得したイメージ・レイヤ ID と対応しません。

このように、バージョン 1.10 前後ではイメージの管理に違いがあります。しかし全ての Docker バージョンにおいて、イメージはレイヤを共有できます。例えば、イメージを pull (取得)する時、既に取得済みの同じイメージ・レイヤがあれば、Docker は状況を認識してイメージを共有します。そして、ローカルに存在しないイメージのみ取得します。2つめ以降の pull は、共通イメージ・レイヤにある2つのイメージを共有しています。

これで、自分で実例を示して理解できるでしょう。 ubuntu:15.04 イメージを使うため、まずは取得(pull)し、変更を加え、その変更に基づく新しいイメージを構築します。この作業を行う方法の1つが、 Dockerfile と docker build コマンドを使う方法です。

  1. 空のディレクトリに、 Dockerfile を作成します。 ubuntu:15.04 イメージの指定から記述します。
FROM ubuntu:15.04
  1. 「newfile」 という名称の新規ファイルを、イメージの /tmp ディレクトリに作成します。ファイル内には「Hello world」の文字も入れます。

作業が終われば、 Dockerfile は次の2行になっています。

FROM ubuntu:15.04

RUN echo "Hello world" > /tmp/newfile
  1. ファイルを保存して閉じます。
  1. ターミナルから、作成した Dockerfile と同じディレクトリ上に移動し、以下のコマンドを実行します。
$ docker build -t changed-ubuntu .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:15.04
 ---> 3f7bcee56709
Step 2 : RUN echo "Hello world" > /tmp/newfile
 ---> Running in d14acd6fad4e
 ---> 94e6b7d2c720
Removing intermediate container d14acd6fad4e
Successfully built 94e6b7d2c720

注釈

上記のコマンドの末尾にあるピリオド(.)は重要です。これは docker build コマンドに対して、現在の作業用ディレクトリを構築時のコンテクスト(内容物)に含めると伝えるものです。

この結果から、新しいイメージのイメージ ID が 94e6b7d2c720 だと分かります。

  1. docker images コマンドを実行します。
  2. Docker ホスト上のローカル・ストレージ領域に、新しい changed-ubuntu イメージが作成されているかどうかを確認します。
REPOSITORY       TAG      IMAGE ID       CREATED           SIZE
changed-ubuntu   latest   03b964f68d06   33 seconds ago    131.4 MB
ubuntu           15.04    013f3d01d247   6 weeks ago       131.3 MB
  1. docker history コマンドを実行します。
  2. 新しい changed-ubuntu イメージが何のイメージによって作成されたか分かります。
$ docker history changed-ubuntu
IMAGE               CREATED              CREATED BY                                      SIZE        COMMENT
94e6b7d2c720        2 minutes ago       /bin/sh -c echo "Hello world" > /tmp/newfile    12 B
3f7bcee56709        6 weeks ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
<missing>           6 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.879 kB
<missing>           6 weeks ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   701 B
<missing>           6 weeks ago         /bin/sh -c #(nop) ADD file:8e4943cd86e9b2ca13   131.3 MB

docker history の出力から、新しい 94e6b7d2c720 イメージ・レイヤが一番上にあることが分かります。 03b964f68d06 レイヤとは、先ほどの Dockerfileecho "Hello world" > /tmp/newfile コマンドでファイルを追加したものだと分かります。そして、4つのイメージ・レイヤは、先ほど ubuntu:15.04 イメージを構築する時に使ったレイヤと一致していることが分かります。

注釈

Docker 1.10 で導入された連想ストレージ・モデル(content addressable storage model)下では、イメージの履歴データは各イメージ・レイヤの設定ファイル上に保存されません。これからは、イメージ全体に関連する、単一の設定ファイル上の文字列に保管されます。これにより、 docker history コマンドを実行したら、いくつかのイメージ・レイヤは「missing」(行方不明)と表示されるでしょう。しかしこれは通常の動作であり、無視して構いません。

これらのイメージを フラット・イメージ (flat images) として読んでいるのを耳にしているかも知れません。

新しい changed-ubuntu イメージは各レイヤのコピーを自分自身で持っていないことに注意してください。下図にあるように、ubuntu:15.04 イメージの下にある4つのレイヤを、新しいイメージでも共有しているのです。

レイヤの共有

また、docker history コマンドは各イメージ・レイヤのサイズも表示します。 94e6b7d2c720 は 12 バイトのディスク容量です。つまり、 changed-ubuntu は Docker ホスト上の 12 バイトのディスク容量しか消費しません。これは、 94e6b7d2c720 よりも下層のレイヤにあたるものが Docker ホスト上に存在しており、これらは changed-ubuntu イメージとして共有されているからです。

このイメージ・レイヤの共有により、Docker イメージとコンテナの領域を効率的に扱えます。

コンテナを効率的にコピー

先ほど学んだように、Docker イメージのコンテナとは、書き込み可能なコンテナ・レイヤを追加したものです。以下の図は ubuntu:15.04 をコンテナのベース・レイヤと下層レイヤを表示しています。

コンテナ・レイヤとイメージ

コンテナに対する全ての書き込みは、書き込み可能なコンテナ・レイヤに保管されます。他のレイヤは読み込み専用(read-only、RO)のイメージ・レイヤであり、変更できません。つまり、複数のコンテナが下層にある1つのイメージを安全に共有できます。以下の図は、複数のコンテナが ubuntu:15.04 イメージのコピーを共有しています。各コンテナは自分自身で読み書き可能なレイヤを持っていますが、どれもが ubuntu:15.04 イメージという単一のインスタンス(イメージ)を共有しています。

レイヤの共有

コンテナの中で書き込み作業が発生したら、Docker はストレージ・ドライバでコピー・オン・ライト処理を実行します。この処理はストレージ・ドライバに依存します。AUFS と OverlayFS ストレージ・ドライバは、コピー・オン・ライト処理を、おおよそ次のように行います。

  • レイヤ上のファイルが更新されていないか確認します。まずこの手順が新しいレイヤに対して行われ、以降は1つ1つのベースになったレイヤをたどります。
  • ファイルに対して初めての処理が始まると「コピー開始」(copy-up)をします。「コピー開始」とは、コンテナ自身が持つ薄い書き込み可能なレイヤから、ファイルをコピーすることです。
  • コンテナの薄い書き込み可能なレイヤに ファイルコピー してから、(そのファイルに)変更を加えます。

BTRFS、ZFS 、その他のドライバは、コピー・オン・ライトを異なった方法で処理します。これらのドライバの手法については、後述するそれぞれの詳細説明をご覧ください。

たくさんのデータが書き込まれたコンテナは、何もしないコンテナに比べて多くのディスク容量を消費します。これは書き込み操作の発生によって、コンテナの薄い書き込み可能なレイヤ上に、更に新しい領域を消費するためです。もしコンテナが多くのデータを使う必要があるのであれば、データ・ボリュームを使うこともできます。

コピー開始処理は、顕著な性能のオーバーヘッド(処理時間の増加)を招きます。このオーバーヘッドは、利用するストレージ・ドライバによって異なります。しかし、大きなファイル、多くのレイヤ、深いディレクトリ・ツリーが顕著な影響を与えます。幸いにも、これらの処理が行われるのは、何らかのファイルに対する変更が初めて行われた時だけです。同じファイルに対する変更が再度行われても、コピー開始処理は行われず、コンテナ・レイヤ上に既にコピーしてあるファイルに対してのみ変更を加えます。

先ほど構築した changed-ubuntu イメージの元となる5つのコンテナに対し、何が起こっているのか見ていきましょう。

  1. Docker ホスト上のターミナルで、 次のように docker run コマンドを5回実行します。
$ docker run -dit changed-ubuntu bash
75bab0d54f3cf193cfdc3a86483466363f442fba30859f7dcd1b816b6ede82d4
$ docker run -dit changed-ubuntu bash
9280e777d109e2eb4b13ab211553516124a3d4d4280a0edfc7abf75c59024d47
$ docker run -dit changed-ubuntu bash
a651680bd6c2ef64902e154eeb8a064b85c9abf08ac46f922ad8dfc11bb5cd8a
$ docker run -dit changed-ubuntu bash
8eb24b3b2d246f225b24f2fca39625aaad71689c392a7b552b78baf264647373
$ docker run -dit changed-ubuntu bash
0ad25d06bdf6fca0dedc38301b2aff7478b3e1ce3d1acd676573bba57cb1cfef

これは changed-ubuntu イメージを元に、5つのコンテナを起動します。コンテナを作成したことで、Docker は書き込みレイヤを追加し、そこにランダムな UUID を割り当てます。この値は、 docker run コマンドを実行して返ってきたものです。

  1. docker ps コマンドを実行し、5つのコンテナが実行中なのを確認します。
$ docker ps
CONTAINER ID    IMAGE             COMMAND    CREATED              STATUS              PORTS    NAMES
0ad25d06bdf6    changed-ubuntu    "bash"     About a minute ago   Up About a minute            stoic_ptolemy
8eb24b3b2d24    changed-ubuntu    "bash"     About a minute ago   Up About a minute            pensive_bartik
a651680bd6c2    changed-ubuntu    "bash"     2 minutes ago        Up 2 minutes                 hopeful_turing
9280e777d109    changed-ubuntu    "bash"     2 minutes ago        Up 2 minutes                 backstabbing_mahavira
75bab0d54f3c    changed-ubuntu    "bash"     2 minutes ago        Up 2 minutes                 boring_pasteur

上記の結果から、 changed-ubuntu イメージを全て共有する5つのコンテナが実行中だと分かります。それぞれの コンテナ ID は各コンテナ作成時の UUID から与えられています。

  1. ローカル・ストレージ領域のコンテナ一覧を表示します。
$ sudo ls containers
0ad25d06bdf6fca0dedc38301b2aff7478b3e1ce3d1acd676573bba57cb1cfef  9280e777d109e2eb4b13ab211553516124a3d4d4280a0edfc7abf75c59024d47
75bab0d54f3cf193cfdc3a86483466363f442fba30859f7dcd1b816b6ede82d4  a651680bd6c2ef64902e154eeb8a064b85c9abf08ac46f922ad8dfc11bb5cd8a
8eb24b3b2d246f225b24f2fca39625aaad71689c392a7b552b78baf264647373

(訳者注:上記コマンドは、 /var/lib/docker ディレクトリで実行してください。)

Docker のコピー・オン・ライト方式により、コンテナによるディスク容量の消費を減らすだけではなく、コンテナ起動時の時間も短縮します。起動時に、Docker はコンテナごとに薄い書き込み可能なレイヤを作成します。次の図は changed-ubuntu イメージの読み込み専用のコピーを、5つのコンテナで共有しています。

レイヤの共有

もし新しいコンテナを開始する度に元になるイメージ・レイヤ全体をコピーするのであれば、コンテナの起動時間とディスク使用量が著しく増えてしまうでしょう。

データ・ボリュームとストレージ・ドライバ

コンテナを削除したら、コンテナに対して書き込まれたあらゆるデータが削除されます。しかし、 データ・ボリューム (data volume) の保存内容は、コンテナと一緒に削除しません。

データ・ボリュームとは、コンテナが直接マウントするディレクトリまたはファイルであり、Docker ホストのファイルシステム上に存在します。データ・ボリュームはストレージ・ドライバが管理しません。データ・ボリュームに対する読み書きはストレージ・ドライバをバイパス(迂回)し、ホスト上の本来の速度で処理されます。コンテナ内に複数のデータ・ボリュームをマウントできます。1つまたは複数のデータ・ボリュームを、複数のコンテナで共有もできます。

以下の図は、1つの Docker ホストから2つのコンテナを実行しているものです。Docker ホストのローカル・ストレージ領域( /var/lib/docker/... )の中に、それぞれのコンテナに対して割り当てられた領域が存在しています。また、Docker ホスト上の /data に位置する共有データ・ボリュームもあります。このディレクトリは両方のコンテナからマウントされます。

共有ボリューム

データ・ボリュームは Docker ホスト上のローカル・ストレージ領域の外に存在しており、ストレージ・ドライバの管理から独立して離れています。コンテナを削除したとしても、Docker ホスト上の共有データ・ボリュームに保管されたデータに対して、何ら影響はありません。

データ・ボリュームに関する更に詳しい情報は、 コンテナでデータを管理する をご覧ください。