ボリュームの使用¶
Docker コンテナによって作成され、かつ、使われるデータを保持するために、ボリュームは適した仕組みです。 バインド マウント はホストマシン上のディレクトリ構造と OS に依存しますが、ボリュームは Docker によって完全に管理されます。バインド マウントと比べ、ボリュームには複数の利点があります。
ボリュームはバインド マウントに比べ、バックアップや
移動 が簡単Docker CLI コマンドや Docker API を使ってボリュームを管理可能
ボリュームは Linux と Windows コンテナの両方で動作
ボリュームは複数のコンテナ間で、より安全に共有可能
ボリューム ドライバによって、リモートホストやクラウドプロバイダに保管でき、ボリューム内容の暗号化や、他の機能性も追加可能
新しいボリュームは、コンテナによって内容を事前に入力可能
Docker Desktop 上のボリュームは、Mac と Windows ホストからのバインド マウントに比べ、より高い性能
加えて、コンテナの書き込み可能なレイヤーにデータを保持するためには、ボリュームがより良い選択です。これは、ボリュームによってコンテナが使用する容量が増えませんし、対象となるコンテナのライフサイクル外でボリュームの内容が存在し続けます。
もしもコンテナが保持する必要がない状態のデータを生成する場合は、 tmpfs マウント の使用を検討ください。それにより、データがどこかに保持される続けるのを防止し、さらに、コンテナの書き込み可能なレイヤーへの書き込みを避けるため、コンテナのパフォーマンスを向上します。
ボリュームは rprivate
-v と --mount フラグの選択¶
一般的に、 --mount
は説明的かつ冗長です。最大の違いは、 -v
構文は1つのフィールドに全てのオプションをつなげるのに対し、 --mount
構文はそれらを分けます。以下は各フラグの比較です。
ボリューム ドライバのオプションの指定が必要であれば、 --mount
を使う必要があります。
-v
か--volume
:コロン記号(:
)で区切られた、3つのフィールドで構成。フィールドは正しい順番で記述する必要があり、それぞれのフィールドの意味は直ちに分からない名前付きボリュームの場合、1つめのフィールドはボリューム名であり、ホストマシン上でユニークな必要がある。無名ボリュームでは、1つめのフィールドは省略する。
2つめのフィールドは、コンテナ内にマウントされるファイルやディレクトリがどこにあるかのパス。
3つめのフィールドはオプションで、
ro
のようなオプションをカンマで区切ったリスト。これらオプションについては、後ほど扱う。
--mount
:複数のキーバリューのペアで構成。それらは、カンマで区切られ、かつ、それぞれが<key>=<value>
のセットで構成。--mount
構文は-v
や--volume
よりも冗長だが、キーの順番は意味が無く、フラグの値は理解しやすい。マウントの
type
(形式)は、bind
、volume
、tmpfs
のどれか。このトピックで扱うのはボリュームのため、形式は常にvolume
。マウントの
source
(マウント元)。名前付きボリュームでは、これがボリューム名になる。無名ボリュームでは、このフィールドは省略。source
もしくはsrc
として指定。destination
(マウント先)の値は、コンテナ内にマウントされるファイルやディレクトリのパスがどこかを示す。destination
、dst
、target
のどれかを指定。readonly
(読み込み専用)オプションがあれば、バインド マウントは 読み込み専用としてコンテナ内にマウント される。readonly か ``ro
で指定。volume-opt
オプションは複数回指定でき、オプション名と値で構成されるキーバリューのペアをとる。
警告
外部の CSV パーサから値をエスケープ
ボリューム ドライバが、オプションでカンマ区切りのリストを受け付ける場合、外部の CSV パーサから値をエスケープする必要があります。 volume-opt
をエスケープするには、ダブルクォート( "
)で囲み、マウント パラメータ全体をシングルクォート( '
)で囲みます。
たとえば、 local
ドライバは o
パラメータ内でカンマで区切ったマウントオプションを受け入れます。以下の例は、リストをエスケープするための正しい方法を表します。
$ docker service create \
--mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
--name myservice \
<IMAGE>
以降の例では --mount
と -v
構文の両方を可能であれば表し、かつ、 --mount
を先に表します。
-v
と --mount
との挙動の違い¶
バインド マウントとは異なり、 --mount
と -v
フラグの両方がボリュームに対するオプションを全て利用できます。
サービスにボリュームを使う場合は、 --mount
のみサポートされます。
ボリュームの作成と管理¶
バインド マウントとは異なり、あらゆるコンテナの範囲外でボリュームの作成や管理ができます。
ボリューム作成:
$ docker volume create my-vol
ボリューム一覧:
$ docker volume ls
local my-vol
ボリュームの :ruby:`調査 <inspect>` :
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
ボリュームを削除:
$ docker volume rm my-vol
ボリュームを使ってコンテナを起動¶
起動するコンテナにボリュームが存在していなければ、 Docker はボリュームを作成します。以下の例はボリューム myvol2
をコンテナ内の /app
にマウントします。
以下の -v
と --mount
例は、どちらも同じ結果になります。一度実行すると、 devtest
コンテナと myvol2
ボリュームを削除しないと、両方実行できません。
--mount
$ docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest
-v
$ docker run -d \
--name devtest \
-v myvol2:/app \
nginx:latest
docker inspect devtest
を使い、ボリュームが作成され、正しくマウントされているのを確認します。 Mounts
セクションを見ます。
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
この表示は、マウントしているのはボリュームであり、正しいマウント元(Source)とマウント先(Destination)が指定され、かつ、マウントは読み書きできます。
コンテナを停止し、ボリュームを削除します。ボリュームの削除は別の手順なので注意してください。
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
docker-compose でボリュームを使う¶
単一の docker compose サービスとボリュームは,次のようなものです。
version: "3.9"
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
docker-compose up
を始めて実行すると、ボリュームが作成されます。続く実行でも、同じボリュームが再利用されます。
ボリュームは docker volume create
によって、 compose の外でも直接作成できます。その場合、以下のように docker-compose.yml
の中で参照します。
version: "3.9"
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
external: true
compose でボリュームを使うための詳しい情報は、 compose リファレンス をご覧ください。
ボリュームとサービスを起動¶
サービスの起動とボリュームの定義時、各サービス コンテナは自身のローカルボリュームを使います。 local
ボリューム ドライバを使う場合は、コンテナ間でデータを共有できませんが、いくつかのボリューム ドライバは共有ストレージをサポートします。Docker for AWS と Docker for Azure の両方で、 Cloudstor プラグインを使ってのデータ保管をサポートします。
以下の例は、4つのレプリカを持つ nginx
サービスを起動し、それぞれが myvol2
と呼ぶローカルボリュームを使います。
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
サービスが実行中かどうかを確認するには、 docker service ps devtest-service
を使います。
$ docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
サービスを削除すると、全てのタスクも停止します。
$ docker service rm devtest-service
サービスを削除しても、サービスによって作成されたボリュームは削除されません。ボリュームの削除とは、別のステップです。
サービスに対する構文の違い¶
docker service create
コマンドは -v
や --volume
フラグをサポートしません。ボリュームをサービスのコンテナ内にマウントするには、 --mount
フラグを使用する必要があります。
コンテナを使ってボリュームを加える¶
コンテナの作成時、先述の通り新しいボリュームを作成し、コンテナが持っているファイルやディレクトリ内に、ディレクトリとしてマウントされます(先ほどの /app/
のように)。このディレクトリの内容は、ボリュームからコピーされたものです。コンテナがマウントした後にボリュームを使用すると、同じボリュームを使う他のコンテナからも、作成された内容にアクセスできます。
これを説明するために、以下の例では nginx
コンテナを起動し、コンテナの /usr/share/nginx/html
ディレクトリ内に新しいボリューム nginx-vol
を作成します。このディレクトリは Nginx の HTML コンテンツをデフォルトで置く場所です。
例にある --mount
と -v
は、どちらも同じ結果になります。
--mount
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
-v
- $ docker run -d
--name=nginxtest -v nginx-vol:/usr/share/nginx/html nginx:latest
これらの例を試した後は、以下のコマンドでコンテナとボリュームを削除します。ボリュームの削除は別のステップなので、気を付けてください。
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
. _use-a-read-only-volume: 読み込み専用のボリュームを使用 ==============================
アプリケーション開発では、コンテナがバインド マウントへの書き込みを必要とするなら、変更は Docker ホスト側へと反映されます。一方で、コンテナがデータの読み込みだけを必要とする場合があります。複数のコンテナは同じボリュームをマウントできるのを思い出してください。これがあれば、一方は読み書きできるようにマウントし、もう一方では読み込み専用としてのマウントが、同時に行えます。
以下は前述の例を変更したもので、コンテナ内へのマウントポイントの後に、 ro
をオプションのリスト(デフォルトは空)に追加し、ディレクトリを
例にある --mount
と -v
は、どちらも同じ結果になります。
--mount
$ docker run -d \ --name=nginxtest \ --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \ nginx:latest
--v
$ docker run -d \ --name=nginxtest \ -v nginx-vol:/usr/share/nginx/html:ro \ nginx:latest
読み込み専用のマウントが正しく作成されたかどうかを確認するには、 docker inspect nginxtest
を使います。 Mounts
セクションを探します。
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol",
"Source": "/var/lib/docker/volumes/nginx-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": false,
"Propagation": ""
}
],
コンテナを停止、削除してから、ボリュームを削除します。ボリュームの削除は別のステップです。
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
マシン間のデータ共有¶
これをアプリケーションの開発時に実現するには、いくつかの方法があります。1つは Amazon S3 のようなクラウド オブジェクト ストレージ システム上に、アプリケーションがファイルを保存するような仕組み(ロジック)の追加です。他の手法は、NFS や Amazon S3 のような外部のストレージ システム上への書き込みをサポートしているドライバを使っての、ボリュームの作成です。
ボリュームドライバにより、アプリケーションの仕組みから、基礎となるストレージシステムを抽象化できるようになります。たとえば、サービスが NFS ドライバでボリュームを使う場合であれば、アプリケーションの仕組みを変更しなくても、クラウド上にデータを保管するなど、異なるドライバを使ってもサービスを更新できます。
ボリュームドライバをの使用¶
docker volume create
を使ってボリュームの作成時や、まだ作成していないボリュームを使うコンテナの起動時に、ボリュームドライバを指定できます。以下は vienx/sshfs
ボリュームドライバを使う例であり、第一に、スタンドアロン ボリュームを作成し、それから新しいボリュームを作成するコンテナを起動します。
初期セットアップ¶
この例では2つのノードがあるものと想定しています。そのうち1つは Docker ホストであり、2つめに SSH を使って接続できます。
Docker ホスト上で、 vienx/sshfs
プラグインをインストールします。
$ docker plugin install --grant-all-permissions vieux/sshfs
ボリュームドライバを使ってボリュームを作成¶
この例では SSH パスワードを指定しますが、2つのホストで鍵設定を共有していれば、パスワードを省略できます。各ボリュームドライバでには設定可能なオプションが無い場合と複数ある場合があり、指定する場合は -o
フラグを使います。
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume
ボリュームドライバを使い、ボリュームを作成するコンテナを起動¶
この例では SSH パスワードを指定しますが、2つのホストで鍵設定を共有していれば、パスワードを省略できます。各ボリュームドライバでには設定可能なオプションが無い場合と複数ある場合があります。 ボリュームドライバにオプションを渡す必要がある場合は、ボリュームのマウントに -v ではなく --mount フラグを使う必要があります 。
$ docker run -d \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest
この例は、サービスの作成時に NFS ボリュームを作成する方法を表します。例では NFS サーバとして 10.0.0.10
を使い、 NFS サーバ上に公開するディレクトリを /var/docker-nfs
とします。ボリュームドライバは local
なので注意します。
NFSv3¶
$ docker service create -d \
--name nfs-service \
--mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,volume-opt=o=addr=10.0.0.10' \
nginx:latest
NFSv4¶
$ docker service create -d \
--name nfs-service \
--mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
nginx:latest
CIFS/Samba ボリュームの作成¶
ホスト上のマウントポイントを変更しなくても、Docker で直接 Samba 共有ディレクトリをマウントできます。
$ docker volume create \
--driver local \
--opt type=cifs \
--opt device=//uxxxxx.your-server.de/backup \
--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \
--name cif-volume
注意として、IP アドレスの代わりにホスト名を使う場合は、docker がホスト名の名前解決をできるようにするため、 addr
オプションが必要になります。
データボリュームのバックアップ、復旧、移行¶
ボリュームはバックアップ、 --volumes-from
フラグを使うと、そのボリュームをマウントします。
ボリュームのバックアップ¶
たとえば、 dbstore
という名前の新しいコンテナを作成します。
$ docker run -v /dbdata --name dbstore ubuntu /bin/bash
それから次のコマンドで行うのは、
新しいコンテナを起動し、
dbstore
コンテナからボリュームをマウントローカルホストディレクトリを
/backup
としてマウントdbdata
ボリュームの内容を tar を使い、手元の/backup
ディレクトリ内のbackup.tar
へ出力するコマンドを渡す
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
コマンドの処理が終わると、コンテナは終了し、手元の dbdata
ボリュームにバックアップが残されます。
バックアップからボリュームを復旧¶
作成したバックアップを使えば、同じコンテナや他の別の場所で作ったコンテナにも復旧できます。
たとえば、 dbstore2
という名前の新しいコンテナを作成します。
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
それから、新しいコンテナ内のデータボリュームに、バックアップファイルを tar で展開します。
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
このテクニックは自動バックアップや移行、復旧テストに、自分の好きなツールを使って行えます。
ボリューム削除¶
Docker のデータボリュームはコンテナを削除した後も残り続けます。2つのボリュームタイプについて考えます。
名前付きボリューム は、コンテナ外に
awsome:/bar
のような指定された参照元がある無名ボリューム は明示的な参照元が無いため、コンテナの削除時、Docker Engine デーモンに対し、ボリュームを削除するよう指示する
無名ボリューム の削除¶
無名ボリュームを自動的に削除するには、 --rm
オプションを使います。たとえば、このコマンドは無名の /foo
ボリュームを作成します。コンテナの削除時、 Docker Engine は /foo
ボリュームを削除しますが、 awesome
ボリュームは削除しません。
$ docker run --rm -v /foo -v awesome:/bar busybox top
注釈
他のコンテナが --volumes-from
でボリュームをバインドすると、ボリュームの定義は「コピーされ」、1つめのコンテナを削除した後も無名ボリュームは残り続けます。
全てのボリュームを削除¶
全ての未使用ボリュームを削除し、空き容量を拡げます。
$ docker volume prune
次のステップ¶
バインド マウント について学ぶ
tmpfs マウント について学ぶ
ストレージ ドライバ について学ぶ
サードパーティ製ボリュームドライバ プラグイン について学ぶ
参考
- Use volumes