Docker数据卷

一、数据卷介绍

容器持久化操作和同步操作,容器间的数据可以共享,使用 run命令的 -v (volume)参数来设置容器数据卷。

大白话就是:数据卷可以理解成,宿主机可以共享容器中的文件,具体哪些文件在启动容器的时候通过-v来指定,而这些文件就可以在宿主机中直接修改,修改后容器中的文件也被更改了,是不是可以想到一些应用场景,如nginx,mysql的配置文件,还有一些日志等,都可以通过数据卷挂载出来,方便修改和查看。这种方式唯一的坏处是,系统中会多一份文件,占用些内存,总的来说,优点还是大于缺点的。

二、数据卷挂载

挂载分为三种方式,分别是匿名挂载,具名挂载,指定路径挂载

注意:容器数据卷挂载时,只能在创建容器时挂载,因为-v 是run命令的一个参数,启动之后就不能再挂载了。
并且,即使容器停止,只要容器还存在,这个关联就一直再,及在本地新增一个文件,容器中也会自动新增,在容器中更改一个文件,本地也会自动更改

2.1 匿名挂载

匿名挂载:-v 容器内路径,匿名挂载只单独指定容器内路径,会在docker的默认工作目录下自动生成一个文件夹,以Centos镜像为例

  • 为了测试方便先删除一下所有的容器和挂载卷,正式服务器请勿使用

    #强制删除所有容器
    docker rm -f $(docker ps -aq)
    
    #删除所有volume
    docker volume rm $(docker volume ls -q)
    
  • 将centos的/home匿名挂载到docker工作目录,该容器名为centos01

    docker run -d -it --name centos01 -v /home centos:latest
    
  • 启动之后镜像就创建好了,可以通过docker volume ls查看匿名的卷名,是一串ID

    docker volume ls
    
    DRIVER    VOLUME NAME
    local     36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246
    
  • 然后通过这个卷名,可以通过docker volume inspect 卷名查看到卷的详细信息,比如它的路径

    docker volume inspect 36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246
    
    [
        {
            "CreatedAt": "2021-09-27T14:48:13+08:00",
            "Driver": "local",
            "Labels": null,
            "Mountpoint": "/var/lib/docker/volumes/36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246/_data",
            "Name": "36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246",
            "Options": null,
            "Scope": "local"
        }
    ]
    
  • 具体挂载效果和这里先不演示,放在指定路径挂载中

2.2 具名挂载

具名挂载:-v 卷名:容器内路径,具名挂载就只是比匿名多了个卷名,将一长串的ID变成了指定名,当然我还可以通过dockerfile的方式挂载,dockerfile的方式本质还是具名挂载,后面讲到dockerfile时再讨论,这里还是以Centos为例

  • 将centos的/home挂载到docker工作目录下的centosvolume目录下,该容器名为centos02

    docker run -d -it --name centos02 -v centosvolume:/home centos:latest
    
    
  • 启动之后,查看卷信息

    docker volume ls
    
    DRIVER    VOLUME NAME
    local     36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246
    local     centosvolume
    
    
  • 查看卷详细信息

    docker volume inspect centosvolume
    
    [
        {
            "CreatedAt": "2021-09-27T15:06:30+08:00",
            "Driver": "local",
            "Labels": null,
            "Mountpoint": "/var/lib/docker/volumes/centosvolume/_data",
            "Name": "centosvolume",
            "Options": null,
            "Scope": "local"
        }
    ]
    

2.3 指定路径挂载

指定路径挂载:-v 宿主机目录:容器目录,指定路径挂载比较常见,可以自定义路径,相对来说更方便一下,以Centos为例测试一下挂载效果

  • 将centos的/home挂载到宿主机的/home/centostest目录,该容器名为centos03

    docker run -d -it --name centos03 -v /home/centostest:/home centos:latest
    
    
  • 启动之后,查看卷信息时发现,此时的卷已经不在此处了,而宿主机中/home目录下多了个centostest文件夹

    docker volume ls
    
    DRIVER    VOLUME NAME
    local     36ebb5e8a88c5cd0814dafa19d366f10564353ed90661055badadec276c47246
    local     centosvolume
    

    这里没有,那他们之间是怎么关联的呢?可以用之前提到的查看容器的元信息命令docker inspect 容器ID或名

    docker inspect centos03 | grep Mounts -A 10
    
    "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/home/centostest",
                    "Destination": "/home",
                    "Mode": "",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ],
    
    
  • 进入/home/centostest测试一下挂载效果,测试挂载是否成功简单,在宿主机中创建一个test.java文件,进入容器,切换到home目录,查看是否存在test.java文件。

    [root@izuf67znusfv5r0k1fzac9z home]# cd centostest/
    [root@izuf67znusfv5r0k1fzac9z centostest]# ls
    [root@izuf67znusfv5r0k1fzac9z centostest]# pwd
    /home/centostest
    [root@izuf67znusfv5r0k1fzac9z centostest]# touch test.java
    [root@izuf67znusfv5r0k1fzac9z centostest]# ls
    test.java
    [root@izuf67znusfv5r0k1fzac9z centostest]# docker exec -it centos03 /bin/bash
    [root@d1055f6874f6 /]# cd home
    [root@d1055f6874f6 home]# ls
    test.java
    [root@d1055f6874f6 home]# exit
    exit
    [root@izuf67znusfv5r0k1fzac9z centostest]# 
    
  • 注意事项

    在使用数据卷挂载时,如果所挂载的宿主机中包含文件,不管容器中是否包含文件,宿主机都将覆盖容器中的文件;如果所挂载的宿主机中不包含文件,容器则将自己的文件复制到宿主机中;并且挂载时,宿主机和容器要么都是文件,要么都是文件夹,如果不同,将启动失败。

三、其他

3.1 数据卷读写权限

数据卷还可设置ro 只读和 rw可读可写,一但设置了容器权限,容器文件就有限制了,这个限制是针对容器内的文件,加上ro,说明这个文件只能通过宿主机来修改。以Centos为例:

限制容器中/home目录的写入功能,

docker run -d -it --name centos04 -v /home/centostest:/home:ro centos:latest

如果在容器中修改,创建文件会失败,提示文件只读

[root@izuf67znusfv5r0k1fzac9z centostest]# docker exec -it centos04 /bin/bash
[root@32b4998b514d /]# cd home
[root@32b4998b514d home]# touch test2.java
touch: cannot touch 'test2.java': Read-only file system
[root@32b4998b514d home]# exit
exit
[root@izuf67znusfv5r0k1fzac9z centostest]# 

3.2 数据卷同步

--volumes-from,创建容器时,数据卷使用其他已经存在的数据卷,这样做的好处是,能使配置文件同步,不用每次都改

将centos的/home挂载到宿主机的centos03的目录下,该容器名为centos05

docker run -d -it --name centos05 --volumes-from centos03 centos:latest

这里就不测试了,在centos03中新建的test.java,也出现在了centos05容器home目录下,home目录下新建一个test3.java文件,centos03中也会有。

3.3 手动创建数据卷

数据卷可以通过docker volume create 数据卷名,这和这个数据卷默认是在docker的工作目录下,尝试一下

[root@izuf67znusfv5r0k1fzac9z work]# docker volume create volumecreate
volumecreate
[root@izuf67znusfv5r0k1fzac9z work]# docker inspect volumecreate
[
    {
        "CreatedAt": "2021-09-27T16:42:33+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/volumecreate/_data",
        "Name": "volumecreate",
        "Options": {},
        "Scope": "local"
    }
]

如果我们此时再次使用具名挂载,并且数据卷名为volumecreate,那么此时docker将不会创建新的数据,如果此时文件夹下有文件,也将在容器被创建时一并同步到容器中。