在之前学docker的时候,一直都是使用-v来创建容器数据卷,理解为宿主机和容器中的一个快速通道。方便修改一些配置文件,以及重要数据文件的持久化。特别是生成数据,如果容器异常或者是被误删,没有备份的数据,将会很麻烦。
之前创建各种容器的时候,也有使用-v创建容器数据卷,也没有特别注意是否创建成功,文件或文件夹是否有映射类的。最近玩儿nacos的时候,想着将logs和conf目录映射到宿主机,便于查看和修改,遇到了一系列问题,迫使自己不得不更深入的了解容器数据卷。好在,还是有成果的。
在宿主机创建/docker/volume/nacos/conf和/docker/volume/nacos/logs两个目录,准备映射容器内部的/home/nacos/conf和/home/nacos/logs,宿主机的两个目录其实是可以不提前创建的,执行docker run的同时,可以自动创建。
执行以下命令,创建nacos容器
docker run \
--name nacos-roswu -d \
-p 8848:8848 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v /docker/volume/nacos/logs:/home/nacos/logs \
-v /docker/volume/nacos/conf:/home/nacos/conf \
nacos/nacos-server
命令执行结束,容器创建成功

但事实上,容器运行有报错,控制台也访问不了
使用docker logs nacos-roswu查看容器运行日志

错误提示缺少文件,但并不止缺少这一个文件。
我们使用docker exec -it nacos-roswu /bin/bash进入容器内部,查看相应目录

容器内部的/home/nacos/conf目录是空的,服务缺少相应的配置,运行自然报错。
由此,使用-v或--volume的方式创建容器数据卷,如果宿主机是空目录,容器内为非空目录,容器内部的文件会被覆盖为空。如果宿主机不是空目录,自然会将相关的文件或目录,映射到容器类的目标目录下。
这种情况,网上大部分的方案都是,再创建另一个容器,使用docker cp将conf和logs下的文件和目录拷贝出来,放到宿主机的对应目录下,宿主机上的文件和目录再映射到容器内。多少有些画蛇添足的意思。
有些容器,创建的时候需要自定义配置,可以提前在宿主机的目录下自行创建文件并编辑后,再docker run创建容器并创建容器数据卷,将配置文件映射到容器内生效。
但,似乎都没有--mount方式好用。
我们先使用docker stop nacos-roswu停掉之前创建的容器,再使用docker rm nacos-roswu删掉。
在创建容器前,需要先了解几个volume相关的命令
docker volume create 创建数据卷
docker volume ls 查看数据卷列表
docker volume inspect 查看一个数据卷的详情
docker volume rm 删除数据卷
下方创建了nacos-conf和nacos-logs两个数据卷,需要注意的是,数据卷的Source目录都在/var/lib/docker/volumes目录下,使用docker volume create创建新的数据卷时,没有办法指定路径,默认为/var/lib/docker/volumes/$VOLUME_NAME/_data

我们使用docker volume inspect nacos-conf 查看以下数据卷的详情

数据卷创建好后,接着就是创建容器了,我们将上面的docker run命令改一下
docker run \
--name nacos-roswu -d \
-p 8848:8848 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
--mount source=nacos-logs,destination=/home/nacos/logs \
--mount source=nacos-conf,destination=/home/nacos/conf \
nacos/nacos-server
命令运行完成,容器创建成功,使用docker logs nacos-roswu查看日志
容器运行成功,接着访问一下控制台

接着,我们还需要看一下宿主机下的数据卷是否有映射成功

-v,是--volume的缩写,只能创建bind mount,当路径不存在时,会自动创建。
--mount,默认挂在volume(不指定type),也可以用来创建bind mount和tmpfs
| 对比项 | bind mount | volume |
|---|---|---|
| Source位置 | 用户指定 | /var/lib/docker/volumes/ |
| Source为空 | 覆盖dest为空 | 保留dest内容 |
| Source非空 | 覆盖dest内容 | 覆盖dest内容 |
| Source种类 | 文件或目录 | 只能是目录 |
| 可移植性 | 一般(自行维护) | 强(docker托管) |
| 宿主直接访问 | 容易(仅需chown) | 受限(需登陆root用户)* |
另外,使用mount的创建volume时,source不能直接使用=绝对路径,但可以使用未创建的数据卷。
比如上方命令中
--mount source=nacos-logs,destination=/home/nacos/logs \
--mount source=nacos-conf,destination=/home/nacos/conf \
数据卷nacos-logs和nacos-conf可以不提前创建,创建容器时可以自动替我们创建,对应的目录仍然在/var/lib/docker/volumes/$VOLUME_NAME/_data
最后一句话总结:-v和--mount type=bind相似,会覆盖容器内的目录和文件,推荐使用--mount type=volume