第一次看到 volumes 这个参数是在一个维基镜像的 docker-compose.yml
文件:
(前置知识 yaml 语法,详细解释可以看一下阮一峰的 YAML 语言教程,TLDR 其实主要两个重点:1 是缩进代表层级结构,2 是同级的 -
代表数组结构。)
据文档所讲 volumes 用于数据持久化,但是第一次看这个配置是完全不懂什么意思,于是我对自己提出了一些问题:
- dokuwiki_data:/bitnami 是什么意思?
- 外面一层的 volumes 又是什么?
- volume 的文件在哪?
- volume 挂载后两边的数据怎么同步?
为了回答这几个问题,当然是要去翻官方文档了,主要内容在这两个页面:Manage data in Docker 和 Use volumes。
docker volume 命令
这是 docker 本身的 volume 命令:
对应上面 docker-compose.yml
的外层 volumes,这就回答了第二个问题。
外面的 volumes 用于创建一个名为 dokuwiki_data 的 volume。
docker run 的 -v 参数
拓展阅读:docker run 文档
docker run
是运行镜像的指令(等于 docker container run
),在使用 -v
参数后指定了 volume 相关设置。
上面例子中的 myvol2:/app
是把一个名为 myvol2(这是一个 volume 名称,你也可以在这里使用绝对地址)的 volume 挂载(mount)到容器的 /app
目录。
现在回答最上面的第一个问题,docker-compose.yml
中 dokuwiki 下的 volume 的值 'dokuwiki_data:/bitnami'
就是直接代入 -v
的,那么答案就很明确了:
把 dokuwiki_data
这个 volume 挂载到容器中的地址 /bitnami
。
volume 所在
volume 在哪这个问题在没看文档之前很是迷惑。一开始以为 /root/xxx:/app
这么写的话文件就在根目录的 xxx 里,结果当然是怎么找不到。
然而实际上 volume 是处于 docker 管理下的 volumes 目录(差不多是这样的 /var/lib/docker/volumes/
)。这么做其实可以有效保护你的主机中的机密文件,毕竟挂载到容器的话,数据就可以全盘读取了。如果上面挂载的时候使用的是绝对地址,就可能存在重要系统重要数据被读取的问题。
docker volume ls
字面意思就是列出你所有的 volume,如果你实在不知道 volume 的准确位置,你可以使用 volume inspect
,Mountpoint
就是某个 volume 的准确位置:
于是回答第三个问题:数据一般储存在 /var/lib/docker/volumes/
,如果找不到这个目录,可以使用 volume inspect
查询具体位置。
volume 怎么运作
这个也是初见 volume 的大疑惑,不过在阅读文档后就很清晰了:
- 如果你挂载了一个空的 volume 到某个容器目录,而那个容器目录里又存在文件,那么,会先把容器目录里的文件先自动复制(propagate)到 volume 目录,这样就把容器里面本来应有的文件填充到了主机的 volume。而如果容器中不存在那个目录,会自动创建。
- 如果你挂载了一个非空 volume,那么容器目录里原有的文件会被遮蔽(obscured) 。关于这个遮蔽,也就是把 volume 挂载到容器目录之后,目录本来的内容不会被删除或修改,但是你在访问那个目录的时候等于直接访问挂载目标。(个人理解,另外官网使用了 Linux 系统的
/mnt
目录作例子)
根据这两条信息,回答第四个问题:一旦使用 volume,那数据就以 volume 内容为准,volume 在开始为空的情况下容器内容会被先复制到 volume,保证初始内容正确,然后程序运行也会直接改变 volume 数据。在实际使用上,把这个修改完的 volume 直接搬运到其他环境再挂载进去就完全没有问题了。
不止如此
当然 volume 不止这么点功能,例如他还能被设置为只读、设置远程 volume 还有备份和恢复等等。而且数据持久化也不止 volume 一个方法,例如 Bind mount 和 tmpfs
mount。知识总是学不完的,如果以后用到,再另作总结吧。