Docker Data Volume 之 bind mount

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。Data Volume 有以下特点:

  1. Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。

  2. 容器可以读写 volume 中的数据。

  3. volume 数据可以被永久的保存,即使使用它的容器已经销毁。

好,现在我们有数据层(镜像层和容器层)和 volume 都可以用来存放数据,具体使用的时候要怎样选择呢?考虑下面几个场景: 

  1. Database 软件 vs Database 数据

  2. Web 应用 vs 应用产生的日志

  3. 数据分析软件 vs input/output 数据

  4. Apache Server vs 静态 HTML 文件

相信大家会做出这样的选择:

  1. 前者放在数据层中。因为这部分内容是无状态的,应该作为镜像的一部分。

  2. 后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开存放。

还有个大家可能会关心的问题:如何设置 voluem 的容量?

因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。

 

bind mount


bind mount 是将 host 上已存在的目录文件 mount 到容器。

 例如 docker host 上有目录 /data/nginx:

[root@localhost ~]# cd /data/nginx/
[root@localhost nginx]# pwd
/data/nginx
[root@localhost nginx]# ls
index.html

 通过 -v 将其 mount 到 nginx容器:

#没有mount之前,可以看到目录/usr/share/nginx/html下面是有两个文件的
[root@localhost nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
77f85615efca        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 2 seconds        80/tcp              affectionate_meninsky
[root@localhost nginx]# docker exec -it 77f85615efca /bin/bash
root@77f85615efca:/# ls /usr/share/nginx/html/
50x.html  index.html

#挂载之后
[root@localhost nginx]# docker run -itd --name=nginx -p 80:80 -v /data/nginx:/usr/share/nginx/html nginx
3c9be3ad8788544f5533f4e1519592f4b37d4a19f4ea584e0b2d96d76d7f510d
[root@localhost nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
3c9be3ad8788        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp   nginx

[root@localhost nginx]# docker exec -it nginx ls /usr/share/nginx/html
index.html
[root@localhost nginx]# cat index.html 
hello nginx
[root@localhost nginx]# docker exec -it nginx cat  /usr/share/nginx/html/index.html
hello nginx

-v 的格式为 <host path>:<container path>。/usr/share/nginx/html/就是nginx存放静态文件的地方。由于/usr/share/nginx/html/已经存在,原有数据会被隐藏起来,取而代之的是/data/nginx中的数据,这与 linux mount 命令的行为是一致的。

更新一下,看是否能生效: 

[root@localhost nginx]# echo "changed" > index.html 
[root@localhost nginx]# curl 192.168.179.99
changed

host 中的修改确实生效了,bind mount 可以让 host 与容器共享数据。这在管理上是非常方便的。

下面我们将容器销毁,看看对 bind mount 有什么影响:

[root@localhost nginx]# docker ps -aq | xargs docker rm -f
3c9be3ad8788
77f85615efca
[root@localhost nginx]# pwd
/data/nginx
[root@localhost nginx]# cat index.html 
changed

可见,即使容器没有了,bind mount 也还在。这也合理,bind mount 是 host 文件系统中的数据,只是借给容器用用,哪能随便就删了啊。

另外,bind mount 时还可以指定数据的读写权限,默认是可读可写,可指定为只读:

[root@localhost nginx]# docker run -itd --name=nginx -p 80:80 -v /data/nginx:/usr/share/nginx/html:ro nginx
e114207e7b6549f1a34a0370a3b10ba3b315ecec34a961752bf8d918182c8108

[root@localhost nginx]# docker exec -it nginx /bin/bash
root@e114207e7b65:/# cd /usr/share/nginx/html/
root@e114207e7b65:/usr/share/nginx/html# ls
index.html
root@e114207e7b65:/usr/share/nginx/html# echo "test" > index.html 
bash: index.html: Read-only file system

ro 设置了只读权限,在容器中是无法对 bind mount 数据进行修改的。只有 host 有权修改数据,提高了安全性。

除了 bind mount 目录,还可以单独指定一个文件:

[root@localhost nginx]# docker run -itd --name=nginx1 -p 88:80 -v /data/nginx/index.html:/usr/share/nginx/html/index.html nginx
e9cdb5621cda810e29afeed85e57cc577ee23d4377aa1cea0d616af847424882
[root@localhost nginx]# docker exec -it nginx1 ls /usr/share/nginx/html
50x.html  index.html
[root@localhost nginx]# curl 192.168.179.99:88
changed

使用 bind mount 单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录。在上面的例子中,我们将 html 文件加到 nginx 中,同时也保留了容器原有的数据。

使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录 bind mount 给容器。

mount point 有很多应用场景,比如我们可以将源代码目录 mount 到容器中,在 host 中修改代码就能看到应用的实时效果。再比如将 mysql 容器的数据放在 bind mount 里,这样 host 可以方便地备份和迁移数据。

[root@localhost webapps]# docker run -itd -v /data/tomcat/webapps:/usr/local/tomcat/webapps -p 8080:8080 tomcat
4b27f8242c648f288aa1471def2dfc30e3835265dad3f1831106b60dc7452336
[root@localhost webapps]# cp /root/ROOT.war .

[root@localhost webapps]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                    NAMES
4b27f8242c64        tomcat              "catalina.sh run"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp   recursing_khayyam


[root@localhost webapps]# docker logs -f 4b27f8242c64
03-Nov-2020 12:14:12.713 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/ROOT.war]
03-Nov-2020 12:14:32.742 INFO [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
03-Nov-2020 12:14:33.578 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/ROOT.war] has finished in [20,866] ms

 bind mount 的使用直观高效,易于理解,但它也有不足的地方:bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。

移植性更好的方式是 docker managed volume,下篇博客我们讨论。 

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页