• docker的volume和bind mount究竟有什么区别?



    不知道你在使用docker的时候,有没有注意到volume mount和bind mount的使用? 进一步说,他们之间的区别到底是什么?

     

    接下来的内容,我们就为你揭开他们的神秘面纱。

     

    相同之处

     

    首先,说相同之处:

     

    volume和bind mount都是持久化容器的机制。

     

     

    不同之处

     

    再来说说,他们的不同之处:

     

      volume是由docker来进行管理的,而bind mount完全是依赖于主机的目录结构和操作系统

     

     

    volume 相对于 bind mount的优点

     

    • volume更加容易进行备份和迁移
    • 可以通过docker客户端命令或者docker api来管理volume (比如:docker volume命令)
    • volume可以在linux和windows容器中运行
    • volume可以更加安全的在多个容器之间进行共享
    • volume驱动程序允许在远程主机或云提供商上存储卷,以加密volume的内容或添加其他功能
    • 新volume的内容可以由容器预先填充
    • Docker Desktop上的卷比Mac和Windows主机上的绑定挂载具有更高的性能。

     

    此外,与将数据持久化到容器的可写层相比,volume通常是更好的选择,因为volume不会增加使用它的容器的大小,而且volume的内容存在于给定容器的生命周期之外。

     

    也就是说,当容器被移除了之后,volume中的内容还是可以独立存在的。

     

    下图演示了volume和bind mount,以及和容器之间的关系图:

     

    我们可以看到:

    • volume是可docker的存储区域相关的
    • bind mount是直接和操作系统相关的

     

    下面,我们分别展示,volume的挂载、使用的一些操作

     

    volume操作

     

    创建容器,使用volume

     

    我们可以通过下面的命令创建一个容器,使用volume

     

     docker run -d \
      --name devtest \
      -v myvol2:/app \
      nginx:latest
     

     

    其中:-v选项,后面的第一个参数myvol2就是volume的名字,如果在容器使用volume时,volume不存在,那么会自动创建这个volume

     

    [root@centos7 ~]# docker volume ls
    DRIVER    VOLUME NAME
    local     myvol2
    [root@centos7 ~]# 

     

     

    可以查看该volume在docker 宿主机上的具体的路径

     

    复制代码
    [root@centos7 ~]# docker volume inspect myvol2
    [
        {
            "CreatedAt": "2022-08-23T22:04:20-04:00",
            "Driver": "local",
            "Labels": null,
            "Mountpoint": "/var/lib/docker/volumes/myvol2/_data",
            "Name": "myvol2",
            "Options": null,
            "Scope": "local"
        }
    ]
    [root@centos7 ~]# 
    复制代码

     

     

    Mountpoint就指明了这个volume在文件系统上的具体位置。

     

    容器通过:-v myvol2:/app 将volume挂载到容器的/app目录中

     

    复制代码
    [root@centos7 ~]# docker exec -it devtest df -h
    Filesystem               Size  Used Avail Use% Mounted on
    overlay                   50G  3.0G   48G   6% /
    tmpfs                     64M     0   64M   0% /dev
    tmpfs                    1.4G     0  1.4G   0% /sys/fs/cgroup
    shm                       64M     0   64M   0% /dev/shm
    /dev/mapper/centos-root   50G  3.0G   48G   6% /app
    tmpfs                    1.4G     0  1.4G   0% /proc/asound
    tmpfs                    1.4G     0  1.4G   0% /proc/acpi
    tmpfs                    1.4G     0  1.4G   0% /proc/scsi
    tmpfs                    1.4G     0  1.4G   0% /sys/firmware
    [root@centos7 ~]# 
    复制代码

     

     

    向/app目录写文件:

     

    docker exec -it devtest bash -c "echo test > /app/myfile.test"

     

     

    查看卷中的文件是否已经被创建

    复制代码
    [root@centos7 ~]# cd /var/lib/docker/volumes/myvol2/_data
    [root@centos7 _data]# ls
    myfile.test
    [root@centos7 _data]# cat myfile.test 
    test
    [root@centos7 _data]# 
    复制代码

     

     

    没错,确实这个文件就是写到了这个目录中了。

     

    注意:这个volume的内容写的过程是由docker来进行管理的。

     

    查看容器中mount信息

     

    复制代码
    docker inspect devtest
            "Mounts": [
                {
                    "Type": "volume",
                    "Name": "myvol2",
                    "Source": "/var/lib/docker/volumes/myvol2/_data",
                    "Destination": "/app",
                    "Driver": "local",
                    "Mode": "z",
                    "RW": true,
                    "Propagation": ""
                }
            ]
    复制代码

     

     

    可以看到Mounts部分的信息:

     

    • Type: volume
    • Source:就是在宿主机上的具体的目录位置
    • Destination: 容器中的挂载路径
    • Driver: volume的驱动程序类型
    • RW: 是否是读写模式

     

    停止容器、移除容器

     

    docker stop devtest
    
    docker rm devtest

     

     

    容器移除后,volume是否还存在吗?

     

    复制代码
    [root@centos7 _data]# docker volume ls
    DRIVER    VOLUME NAME
    local     myvol2
    [root@centos7 _data]# ls
    myfile.test
    [root@centos7 _data]# cat myfile.test 
    test
    [root@centos7 _data]# 
    复制代码

     

     

    和你想的一模一样,volume还在,其中的写入的内容,仍然存在

     

    移除volume

     

    docker volume rm  myvol2

     

     

    注意!

     

    移除容器和移除volume是2个独立的操作。

     

    使用容器填充volume

     

    另外一个非常重要的点:如果将volume挂载到目录中,如果目录中原来就是有文件或子目录的,那么挂载之后,会将内容拷贝到卷中来。

     

    啥意思?

     

    比如,我们有个镜像,在/app目录下有个a.log文件

     

    复制代码
    [root@centos7 test-volume]# ls
    a.log  Dockerfile
    [root@centos7 test-volume]# cat a.log 
    123456
    12345
    [root@centos7 test-volume]# cat Dockerfile 
    from nginx:latest
    RUN mkdir /app
    copy a.log /app/a.log
    [root@centos7 test-volume]# 
    复制代码

     

    # 构建镜像
    docker build -t vol:2 .

     

     

    挂载数据卷

     docker run -d   --name=vo3   -v nginx-vo3:/app   vol:2

     

     

    发现容器运行后,/app目录下的文件,被拷贝到volume中

     

    复制代码
    [root@centos7 test-volume]# cd /var/lib/docker/volumes/nginx-vo3/_data
    [root@centos7 _data]# ls
    a.log
    [root@centos7 _data]# cat a.log 
    123456
    12345
    [root@centos7 _data]# 
    复制代码

     

     

    而没有,覆盖!这个点,十分的有意思!之前肯定你没有关注过!

     

    以只读方式挂载volume

     

    如何以只读的方式挂载volume,方法非常的简单:

     

    只需要加上ro选项即可

     

    -v nginx-vol:/usr/share/nginx/html:ro

     

    示例:

     

     docker run -d \
      --name=nginxtest \
      -v nginx-vol:/usr/share/nginx/html:ro \
      nginx:latest

     

     

    查看容器的Mounts部分的信息

    docker inspect nginxtest

     

     

    复制代码
            "Mounts": [
                {
                    "Type": "volume",
                    "Name": "nginx-vol",
                    "Source": "/var/lib/docker/volumes/nginx-vol/_data",
                    "Destination": "/usr/share/nginx/html",
                    "Driver": "local",
                    "Mode": "ro",
                    "RW": false,
                    "Propagation": ""
                }
            ]
    复制代码

     

    发现:"RW": false,也就是,非Read-Write的模式

     

    试试向其中写入文件:

     

    [root@centos7 ~]# docker exec -it nginxtest bash -c "echo 1234 > /usr/share/nginx/html/1.log "
    bash: line 1: /usr/share/nginx/html/1.log: Read-only file system
    [root@centos7 ~]# 

     

     

    和你猜的一样,会提示:只读文件系统。

     

    OK,OK,说完了volume的原理,相关的操作,接下来,要看的就是bind mount

     

    bind mount

     

    使用bind mount时,将宿主机上的文件或者目录挂载到容器上。文件或者目录在主机上,是以绝对路径的方式来使用。

    相比之下,当使用volume时,在主机上的Docker存储目录中创建一个新目录,由Docker管理该目录的内容。

     

    要挂载的文件或目录不需要在Docker主机上已经存在。如果它还不存在,则按需创建它。bind mount的性能非常好,但是它们依赖于主机的文件系统具有特定的目录结构。

     

    建议:如果你正在开发新的Docker应用程序,请考虑使用命名的volume。因为,对于bind mount来说,你不能使用Docker CLI命令来直接管理。

     

    使用bind mount启动容器

     

    使用以下得命令,将一个容器通过bind 挂载的方式,将宿主机的目录,挂载到容器中

     

     docker run -d \
      -it \
      --name devtest \
      -v "$(pwd)"/target:/app \
      nginx:latest

     

     

     

    查看容器的bind挂载情况

     

    docker inspect devtest

     

     

    复制代码
            "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/tmp/source/target/target",
                    "Destination": "/app",
                    "Mode": "",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ]
    复制代码

     

    可以看到

     

    • Type : 挂载的类型是bind
    • source: 宿主机上的目录,当然这里使用$(pwd)变量来获取当前的工作目录

     

    关闭、删除容器

     docker container stop devtest
     docker container rm devtest

     

     

    OK,接下来的这个点,非常的关键,如果绑定挂载到容器中的一个非空的目录会如何?

     

    绑定到容器的非空目录

     

    nginx镜像中/usr/share/nginx/html是非空的,有登录页

    复制代码
     docker run -d \
      -it \
      --name non-empty \
      -v /tmp/soure/base:/usr/share/nginx/html \
      nginx:latest  
    [root@centos7 base]# docker exec -it non-empty ls /usr/share/nginx/html
    [root@centos7 base]# 
    复制代码

     

     

    发现,挂载了之后,是空的,也就是把镜像中的内容给覆盖了。

     

    这个和volume是一个巨大的区别!注意

     

    总结

     

    OK,我们这里总结一下,让你更好的理解voLume 和 bind 类型的挂载的区别:

     

    • 管理方式,volume由docker管理,docker客户端命令可操作,bind挂载不行
    • 容器中有内容的目录,volume会复制,bind mount直接将容器中的内容覆盖
    • bind mount可以设置 bind 传播参数。
    • volume可以设置驱动程序

     

    后面的文章中,会带你看看,如何安装volume驱动,来创建特定类型的volume,实现多个节点间的数据共享······

  • 相关阅读:
    ArcGIS解决栅格边界黑边
    如何自动关闭Oracle数据库服务并重启服务器
    Python实战:使用requests通过post方式提交json数据
    linuxPTP参数详解
    一次 G1 堆大小不均问题的排查及解决
    【广州华锐视点】VR飞行员驾驶模拟实训系统
    Linux的目录结构(介绍主要的)
    [MRCTF2020]套娃
    oracle分组合并数值带顺序
    【线性表】—不带头单向非循环链表的增删查改
  • 原文地址:https://www.cnblogs.com/chuanzhang053/p/16620053.html