【Docker再入門】~Dockerデータ管理偏~
はじめに
こんにちは。championです。
普段は、Google CloudやAWSを中心としたクラウドインフラの設計~保守運用を行なっています。
前回の記事では、Docker環境のネットワークについて解説しました。
今回は、Dockerでのデータ管理について解説します。
Docker Storage
Dockerでのデータ管理方法
Dockerコンテナ内で作成されたファイル等のデータは、コンテナが削除されると一緒に消えてしまいます。これはLinuxの名前空間という機能によりコンテナのプロセスごとに独立したファイルシステムを持つため、コンテナ(プロセス)が削除され、新たにコンテナ(プロセス)が作成されると全く別の名前空間が作成され、そのファイルシステムを利用するためファイルの引継ぎはできないです。
コンテナを作成し、コンテナ内にファイルを作成したあと、コンテナ内から抜けます。
$ docker container run -dit --name alpine-linux alpine
20f9fdf613b700adb2424d157c5b04dcd24a25daea42e1f015af6a3691cb262d
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20f9fdf613b7 alpine "/bin/sh" 2 seconds ago Up 2 seconds alpine-linux
$ docker container exec -it alpine-linux /bin/sh
/ # touch ~/text.txt
/ # ls ~/text.txt
/root/text.txt
/ # exit
コンテナを停止し、削除します。
$ docker container stop alpine-linux
alpine-linux
$ docker container rm alpine-linux
alpine-linux
再度、同じコンテナを作成してコンテナ内に入って先ほど作成したファイルを確認しようとすると、/root/text.txt: No such file or directoryと表示されファイルが引き継がれていないことが確認できます。
$ docker container run -dit --name alpine-linux alpine
770665894aaf569c4d06a84312888321db59dfdaa24cf6e4eb643416e5eecfbe
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
770665894aaf alpine "/bin/sh" 7 seconds ago Up 6 seconds alpine-linux
$ docker container exec -it alpine-linux /bin/sh
/ # ls ~/text.txt
ls: /root/text.txt: No such file or directory
/ # exit
コンテナ内で作成したデータをホスト上に保存したい、別のコンテナからも共有して使用したいといったデータの永続性を実現するための技術としてDockerはいくつかのマウント機能を提供しています。
マウント
volumeマウント
volumeマウントは、Docker によって管理されているホストファイルシステム上の一部にデータを保管します。Linuxホスト上では /var/lib/docker/volumesディレクトリ配下を使用します。docker volume lsコマンドを実行することで、volumeの一覧を確認することができます。また、docker volume createコマンドを実行することで、新規のボリュームを作成することができ、ボリュームの詳細情報を確認したい場合はdocker volume inspectコマンドを実行することで、確認することができます。
$ docker volume ls
DRIVER VOLUME NAME
$ docker volume create vm1
vm1
$ docker volume ls
DRIVER VOLUME NAME
local vm1
$ docker volume inspect vm1
[
{
"CreatedAt": "2025-01-31T21:07:16Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/vm1/_data",
"Name": "vm1",
"Options": null,
"Scope": "local"
}
]
ボリュームを作成すると、ホスト側の /var/lib/docker/volumes ディレクトリ配下に新たにvm1ディレクトリが作成され、このディレクトリとコンテナ内がマウントされます。
$ sudo ls -ltr /var/lib/docker/volumes/vm1/
total 0
drwxr-xr-x. 2 root root 6 Jan 31 21:07 _data
ボリュームが作成されたので、コンテナを作成し、ボリュームマウントしていきます。コンテナにボリュームをマウントさせるためには、docker container runコマンドに「--mount」オプションを付与します。「--mount」オプションには、いくつか引数をとります。typeには、マウントの種類を指定します。今回はボリュームマウントのため、type=volumeを指定します。srcには、作成したボリューム名を指定します。今回はsrc=vm1を指定します。targetには、マウントに利用するコンテナのフォルダを指定します。今回はtarget=/homeとしました。
$ docker container run -dit --name alpine-linux1 --mount type=volume,src=vm1,target=/home alpine
9d08bc94b020ffb145fb958249c6206e6a271cce095501db47534175dfe68ef5
ボリュームマウントをしてコンテナを起動したあと、コンテナ内に入り、マウントしたディレクトリ配下でtest.txtファイルを作成し、コンテナから抜けます。その後、コンテナを停止・削除した後、再度ボリュームマウントをしてコンテナを起動し先ほど作成したファイルを確認するとtest.txtファイルが確認できました。
$ docker container exec -it alpine-linux1 /bin/sh
/ # cd /home
/home # touch test.txt
/home # ls test.txt
test.txt
/home # exit
$ docker container stop alpine-linux1
alpine-linux1
$ docker container rm alpine-linux1
alpine-linux1
$ docker container run -dit --name alpine-linux1 --mount type=volume,src=vm1,target=/home alpine
f4647b31d7eead2d4a24dc9306dec81989446816814b397edb4dcac5d23482b2
$ cd /home
$ docker container exec -it alpine-linux1 /bin/sh
/ # cd /home
/home # ls test.txt
test.txt
Docker によって管理されているホストファイルシステム上(/var/lib/docker/volumesディレクトリ配下)を確認すると、コンテナ内で作成したtest.txtファイルが存在することが確認できます。よって、コンテナ内で作成されたファイルはDocker によって管理されているマウント先に存在することになり、コンテナが削除され、再度別のコンテナを起動しても同じマウント先を指定することにより永続化することができます。
$ sudo ls -ltr /var/lib/docker/volumes/vm1/_data
total 0
-rw-r--r--. 1 root root 0 Jan 31 21:26 test.txt
作成したボリュームは、docker volume rmコマンドを利用することで削除することができます。
$ docker volume ls
DRIVER VOLUME NAME
local vm1
$ docker volume rm vm1
vm1
$ docker volume ls
DRIVER VOLUME NAME
bind mount
bindマウントは、ホストマシン上のディレクトリをコンテナにマウントします。volumeマウントを使用することが推奨されていますが、コンテナに設定ファイルを即時反映させたい場合などにbindマウントは利用されます。
bindマウントを利用したコンテナを作成してみましょう。
ホストマシン上に作業ディレクトリworkを作成し、workディレクトリ内にtext.txtファイルを作成しておきます。次にホストマシン上のworkディレクトリとコンテナのhomeディレクトリをbindマウントさせて起動します。
bindマウントさせるためには、volumeマウントと同様にdocker container runコマンドに「--mount」オプションを付与します。「--mount」オプションには、いくつか引数をとります。typeには、マウントの種類を指定します。今回はボリュームマウントのため、type=bindを指定します。srcには、作成したボリューム名を指定します。今回はsrc=$(pwd)を指定します。targetには、マウントに利用するコンテナのフォルダを指定します。今回はtarget=/homeとしました。
$ mkdir work
$ cd work
$ echo "Hello" >> text.txt
$ cat text.txt
Hello
$ docker container run -it --name alpine-linux --mount type=bind,src="$(pwd)",target=/home alpine
/ # ls /home
text.txt
/ # cat /home/text.txt
Hello
ホストマシン上で作成したファイルがコンテナからも確認することができました。このようにbindマウントを使うとホストマシンの好きなディレクトリとコンテナを接続させることができます。
tmpfs
tmpfsマウントは、Linuxホストマシン上のメモリ空間上にマウントします。ホストマシン上のメモリを利用するためアクセスは高速になりますが、コンテナを停止したり、ホストマシン上も停止や再起動をするとデータが消えてしまいます。
tmpfsマウントさせるためには、docker container runコマンドに「--mount」オプションにtype=tmpfsを指定します。targetは、今回もtarget=/homeとしました。コンテナを起動後、コンテナ内でdf -hコマンドを実行すると /home 配下がtmpfsをマウントしていることがで確認できます。
$ docker container run -dit --name alpine-linux1 --mount type=tmpfs,target=/home alpine
c1ce74087a6284c6f2dafa849aaf1c562adb6353de2cbffc9226d56d72a5e9f4
$ docker container exec -it alpine-linux1 /bin/sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
overlay 19.7G 3.7G 16.1G 19% /
tmpfs 64.0M 0 64.0M 0% /dev
shm 64.0M 0 64.0M 0% /dev/shm
tmpfs 1.8G 0 1.8G 0% /home
/dev/sda2 19.7G 3.7G 16.1G 19% /etc/resolv.conf
/dev/sda2 19.7G 3.7G 16.1G 19% /etc/hostname
/dev/sda2 19.7G 3.7G 16.1G 19% /etc/hosts
tmpfs 1.8G 0 1.8G 0% /proc/acpi
tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs 1.8G 0 1.8G 0% /proc/scsi
tmpfs 1.8G 0 1.8G 0% /sys/firmware
Dockerのデータ管理について解説を行ってきました。マウント方法としてはvolume、bind、tmpfsと三種類ありますが、基本的にはvolumeを使う方がよいでしょう。
参考
Discussion