ボリュームとは
- Dockerにおけるボリュームとは、コンテナ内で作成されたデータをホストマシンに保存して永続化するための仕組み(例外あり)
- コンテナが再作成された場合等でも同じボリュームをマウントすることでデータを再利用することが可能となる
ボリュームの種類
- ボリュームには大きく3種類ある
ボリューム
- 本記事で触れるものはこれ
- データは
/var/lib/docker/volumes/
以下に保存される - Dockerの管理下でストレージ領域を確保する
- 名前付きボリューム(ユーザが名前を指定するもの)と匿名ボリューム(名前が自動生成されたハッシュ値のもの)の2種類がある
- 他のプロセスから参照することができないため安全である
- 基本的にはこの方式を使用すれば良い
バインドマウント
- ホスト側のディレクトリをコンテナ内のディレクトリと共有する
tmpfs
- メモリ上に一時的なストレージ領域を確保する
- 機密性の高い情報のマウントに使用されることがあるそう
ボリュームの作成・確認
# ボリュームの作成
$ docker volume create example
example
# ボリューム一覧の確認
# ボリュームが作成されていることが分かる
$ docker volume ls
DRIVER VOLUME NAME
local example
# ボリュームの詳細情報の確認
# Mountpointを見るとボリュームのデータが /var/lib/docker/volumes/example/_data に保存されていることが分かる
$ docker volume inspect example
[
{
"CreatedAt": "2023-01-30T12:33:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/example/_data",
"Name": "example",
"Options": {},
"Scope": "local"
}
]
# しかし上記のMountpointで出力されたパスを確認しても存在しない
$ ls /var/lib/docker/volumes/example/
"/var/lib/docker/volumes/example/": No such file or directory (os error 2)
- ちなみに
docker run
する際に--volume
/-v
や--mount
オプションを指定することで、docker volume create
をしなくても自動でボリュームが作成される
なぜ存在しないのか
- Docker Desktop for Macでは、HyperKitを用いたVMの上でLinuxを起動し、その上でさらにDockerが動作している
- GitHub: https://github.com/moby/hyperkit
- そのため、VMの中でボリュームが作成されており、ホストマシンから直接参照することができない
- こういった仕組みになっている理由は、DockerがLinux上で動作させることを前提としている(名前空間の機能等)ため(だと思われる)
- ちなみにHyperKitはHypervisor.frameworkに対応した仮想化ツールでbhyveやxhyveをベースにしている
- ちなみにHyperKitの他にもVPNKitやDataKitといったDocker Desktop for Macを構成するために必要な機能があり、こちらもOSSとして公開されている
- GitHub: https://github.com/moby/vpnkit
- GitHub: https://github.com/moby/datakit
- ちなみにDocker Desktop for Apple siliconではAppleがVirtualization.frameworkに移行したことからHyperKitは使用されていないそう(Docker Desktop for Macもこちらに移行するかもしれそうだが詳細は不明)
今度こそボリュームを確認する
- VMに入るには
nsenter
を使用すると良い -
nsenter
はenter into namespaces
が由来 - 他の名前空間に入ってプログラムを実行するためのCLI
-
util-linux
パッケージに含まれている - 内部的に使用しているシステムコールは
setns
- nsenterの実装のコメントにも記述がある: https://github.com/util-linux/util-linux/blob/master/sys-utils/nsenter.c#L2
-
nsenter
を簡単に利用するためのDockerイメージが用意されているため、今回はこちらを利用する-
PID=1
のプロセスの名前空間へnsenter
するための最小イメージを提供するもの - Docker Desktop for Macにおいては、結果的にVMに入ることができるということ
- GitHub: https://github.com/justincormack/nsenter1
-
# --privileged は特権モードで、ホストへフルアクセスするための設定
# --pid=host はホストのプロセスIDをコンテナ内から認識できるようにする設定
$ docker run -it --rm --privileged --pid=host justincormack/nsenter1
Unable to find image 'justincormack/nsenter1:latest' locally
latest: Pulling from justincormack/nsenter1
5bc638ae6f98: Pull complete
Digest: sha256:e876f694a4cb6ff9e6861197ea3680fe2e3c5ab773a1e37ca1f13171f7f5798e
Status: Downloaded newer image for justincormack/nsenter1:latest
# ボリューム以外にも様々なデータが保存されている
/ # ls /var/lib/docker/
buildkit image overlay2 runtimes tmp volumes
containers network plugins swarm trust
# 先程作ったボリュームの実体はこれ
/ # ls /var/lib/docker/volumes/example/
_data
ついでにVMの情報を確認する
- どうやらHyperKit上でLinuxKit(コンテナランタイム特化のLinux Subsystem)が動作している模様
# ホスト名の確認
/ # hostname
docker-desktop
# カーネルのリリース番号の表示
/ # uname -r
5.10.104-linuxkit