数据卷是为了保存用户需要保存的数据

数据卷挂载

#创建数据存储文件
[root@docker docker]#mkdir -p /web/app
#创建挂载容器
[root@docker docker]#docker run  -it --name volume -v /web/app centos
[root@docker docker]# docker run -it -d centos /bin/bash
d1eb81de80ec6e8e442f0ad6ba195c3e31d37ef9628317d823dfc8baa715f09b
[root@docker docker]# ls /web
app

查看挂载信息

docker inspect volume

[root@docker docker]# docker inspect volume

 ......
         "Mounts": [
            {
                "Type": "volume",
                "Name": "c46e1c050f9f5820ed9d764d9e2bf291db45040c3b38f47ab7e3a92d0281f4df",
                "Source": "/var/lib/docker/volumes/c46e1c050f9f5820ed9d764d9e2bf291db45040c3b38f47ab7e3a92d0281f4df/_data",
                "Destination": "/web/app",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
.....

宿主机在/var/lib/docker/volumes/下自动生成了挂载目录

手动指定挂载目录

-v 宿主机目录(或文件)路径:容器内映射路径

例如:

[root@docker docker]# docker run \
> -v /web/app:/app \
> -it -d --name test nginx /bin/bash 
50bfd04e58307dba9b9edee9cbf58254f0bbb2b2508db76169fd4705631e053f

docker inspect查看容器test 状态及挂载信息

[root@docker docker]# docker ps -a
CONTAINER ID   IMAGE             COMMAND                   CREATED              STATUS                   PORTS     NAMES
50bfd04e5830   nginx             "/docker-entrypoint.…"   About a minute ago   Up About a minute        80/tcp    test
[root@docker docker]# docker inspect test
.....
"Mounts": [
            {
                "Type": "bind",
                "Source": "/web/app",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
.....

进入test容器

[root@docker docker]# docker attach test
root@50bfd04e5830:/# ls /
app  boot  docker-entrypoint.d     etc   lib    media  opt   root  sbin  sys  usr
bin  dev   docker-entrypoint.sh  home  lib64  mnt    proc  run     srv   tmp  var
root@50bfd04e5830:/# 
root@50bfd04e5830:/# ls /app/

可以看到容器内根目录下有新的/app目录,并且没有内容

接下来

#宿主机操作
[root@docker ~]# cd /web/app/
[root@docker app]# touch a.txt b.txt
[root@docker app]# ls
a.txt  b.txt
#容器内查看
root@50bfd04e5830:/# ls /app/
a.txt  b.txt
root@50bfd04e5830:/# 

可以发现挂载目录数据同步

设置权限

如果需要为数据卷设置只读权限:

[root@docker app]# docker run -it --name volume -v /src/test:/webapp:ro nginx /bin/bash

-v /src/test:/webapp:ro将数据卷权限设置为ro(只读)

查看挂载情况

[root@docker app]# docker inspect volume
....
"Mounts": [
            {
                "Type": "bind",
                "Source": "/src/test",
                "Destination": "/webapp",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            }
        ],
...

发现为ro只读模式

使用DOckerfile 挂载数据卷

用户创建镜像时,通常会在Dockerfile文件中加上 VOLUME[/date]来创建含有数据卷的镜像,并使用该镜像创建包含数据卷的容器。

Dockerfile可以创建多个数据卷,与使用docker run命令创建数据卷不同,Dockerfile中的数据卷不能映射到已经存在的本地目录。在启动容器时,才会创建Dockerfile中指定的数据卷,并且以Dockerfile中指定的名称命名。运行同样镜像的容器创建的数据卷是不一样的(可以看到不同容器的数据卷地址也是不一样的)。当容器中的数据卷地址不一样时,容器之间就无法共享数据了。
下面使用Dockerfile中的VOLUME选项来指定挂载数据卷,首先创建Dockerfile并添加内容,
示例代码如下:

[root@docker ~]# vi Dockerfile
FROM centos-ali/vim
VOLUME /root/data
VOLUME /work
VOLUME test

以上示例创建了一个Dockerfile文件并添加了内容,即挂载三个数据卷。

接下来根据这个创建新镜像

[root@docker ~]# docker build -t volume .
[+] Building 0.2s (5/5) FINISHED                                                                         docker:default
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 100B                                                                               0.0s
 => [internal] load metadata for docker.io/centos-ali/vim:latest                                                   0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => CACHED [1/1] FROM docker.io/centos-ali/vim:latest                                                              0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:c786f7195633b904411d82fe8fadbe470302f85e95048b0561d9c0e762a32c32                       0.0s
 => => naming to docker.io/library/volume      

以上示例中,镜像已经构建完成,并且执行了挂载三个数据卷的命令。

下面使用构建完成的镜像运行容器,并查看其挂载信息,示例代码如下:

[root@docker ~]# docker run -it volume
[root@34dd09f6449c /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  test  usr  work
dev  home  lib64  media       opt  root  sbin  sys  tmp   var

[root@34dd09f6449c /]# exit
exit
#退出后查看挂载情况
[root@docker ~]# docker inspect 34d
....
"Mounts": [
            {
                "Type": "volume",
                "Name": "8082f8bf30382b5eff4ca43d5aed94b339dc124d63739ea6fcc5f2dd3e1759f5",
                "Source": "/var/lib/docker/volumes/8082f8bf30382b5eff4ca43d5aed94b339dc124d63739ea6fcc5f2dd3e1759f5/_data",
                "Destination": "/work",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
.....

从以上示例中可以看出,该容器挂载了三个数据卷,容器内的目录为Dockerfile中指定的目录,宿主机中数据卷的位置在/var/lib/docker/volumes/下,并且数据卷的地址是随机生成的。

如此一来,就实现了通过Dockerfile创建镜像,运行容器时会自动挂载数据卷。

数据卷容器

运行容器时宿主机会随机生成挂载目录,无法保持目录地址一致,所以无法实现容器间的数据共享。数据卷容器可以有效地解决这个问题:将已命名的容器挂载数据卷,其他容器通过挂载这个容器实现数据共享,挂载数据卷的容器叫作数据卷容器。数据卷容器挂载一个宿主机目录,其他容器连接数据卷容器来实现数据的共享

下面启动一个名为 volume-container的容器,此容器包含两个数据卷/volumel和/volume2(这两个数据卷目录在容器中,运行容器时会自动创建),示例代码如下:

[root@docker ~]# docker  run -it --name volume-container -v /volume1 -v /volume2 centos
[root@f8d3844af4b9 /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var      volume2
dev  home  lib64  media       opt  root  sbin  sys  usr  volume1

以上示例中,容器volume-container已经创建完成,数据卷也挂载完成。下面使用Ctrl+P+Q组合键退出当前容器终端,查看挂载信息并在宿主机中为数据卷添加文件,示例代码如下:

[root@docker ~]# docker inspect volume-container | grep volume
        "Name": "/volume-container",
                "Type": "volume",
                "Source": "/var/lib/docker/volumes/6aac0390812b71d45ac1bde6e65758215cabbd305a580d6d91963f5530905d59/_data",
                "Destination": "/volume1",
                "Type": "volume",
                "Source": "/var/lib/docker/volumes/897ee8fcdbf3d866d78973d996069e8c1ea3a63f136c0e10afcbb10f099e9b16/_data",
                "Destination": "/volume2",
                "/volume1": {},
                "/volume2": {}
#查看挂载信息
[root@docker ~]# cd /var/lib/docker/volumes/6aac0390812b71d45ac1bde6e65758215cabbd305a580d6d91963f5530905d59/_data/
[root@docker _data]# ls
[root@docker _data]# echo hello container1 >a.txt
[root@docker _data]# cd /var/lib/docker/volumes/897ee8fcdbf3d866d78973d996069e8c1ea3a63f136c0e10afcbb10f099e9b16/_data/
[root@docker _data]# echo hello container2 >b.txt

以上示例在宿主机中分别为两个数据卷添加文件及文件内容。
下面创建容器 testl-container,用-volumes-from,参数挂载容器 volume-container中的数据卷,示例代码如下:

[root@docker _data]# docker run -it --name test1-container --volumes-from volume-container centos
[root@b542374e57df /]# ls 
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var      volume2
dev  home  lib64  media       opt  root  sbin  sys  usr  volume1
[root@b542374e57df /]# cat /volume1/a.txt 
hello container1
[root@b542374e57df /]# cat /volume2/b.txt 
hello container2

从以上示例中可以看出,两个容器实现了数据共享。
下面将初始数据卷容器删除,观察数据卷还能否正常工作,示例代码如下:

[root@docker _data]# docker ps -a
CONTAINER ID   IMAGE             COMMAND                   CREATED             STATUS                           PORTS     NAMES
b542374e57df   centos            "/bin/bash"               4 minutes ago       Up 3 minutes                               test1-container
f8d3844af4b9   centos            "/bin/bash"               28 minutes ago      Up 28 minutes                              volume-container
[root@docker _data]# docker stop volume-container 
volume-container
#删除了数据卷容器
[root@docker _data]# docker rm volume-container 
volume-container
[root@docker _data]# docker ps -a
CONTAINER ID   IMAGE             COMMAND                   CREATED             STATUS                           PORTS     NAMES
b542374e57df   centos            "/bin/bash"               4 minutes ago       Up 4 minutes                               test1-container
[root@docker _data]# docker run -it --name test2-container --volumes-from test1-container centos
[root@a7dba2da7acf /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var      volume2
dev  home  lib64  media       opt  root  sbin  sys  usr  volume1
[root@a7dba2da7acf /]# cat /volume1/a.txt 
hello container1
[root@a7dba2da7acf /]#  cat /volume2/b.txt
hello container2

从以上示例中可以看到,即使删除了初始的数据卷容器volume-container或其他容器,只要有容器在使用该数据卷,里面的数据就不会丢失。

下面删除所有容器,再观察数据卷,示例代码如下:

#删除所有容器
[root@docker _data]# docker rm `docker ps -a | grep Exited|awk '{print $1}'
#查看数据`
[root@docker _data]# cd /var/lib/docker/volumes/897ee8fcdbf3d866d78973d996069e8c1ea3a63f136c0e10afcbb10f099e9b16/_data/
[root@docker _data]# ls
b.txt
[root@docker _data]# cat b.txt 
hello container2
#数据还在

备份数据卷

企业中,业务数据不容有失。人们通常会对数据进行一次备份或多次备份,以保证数据的安全性。
下面创建一个名为data- volume的 CentOS容器,准备对其挂载的两个数据卷/var/volume1和/var/volume2进行备份操作。示例代码如下:

[root@docker _data]# docker run -it --name data-volume -v /var/volume1 -v /var/volume2 centos
[root@ee9bc9586288 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@ee9bc9586288 /]# ls /var
adm    crash  empty  games   kerberos  local  log   nis  preserve  spool  volume1  yp
cache  db     ftp    gopher  lib       lock   mail  opt  run       tmp    volume2

以上示例中,容器已经创建完成,数据卷也成功挂载。
下面在容器挂载目录中创建文件并添加内容,示例代码如下:

[root@ee9bc9586288 /]# echo hello container1 >/var/volume1/a.txt
[root@ee9bc9586288 /]# echo hello container1 >/var/volume2/b.txt
[root@ee9bc9586288 /]# echo hello container2 >/var/volume2/b.txt
[root@ee9bc9586288 /]# cat /var/volume1/a.txt
hello container1
[root@ee9bc9586288 /]# cat /var/volume2/b.txt
hello container2

简而言之,备份数据卷就是使用 -volumes-from参数来创建一个挂载数据卷的容器,从宿主机挂载要存放备份数据的目录到容器的备份目录,并备份数据卷中的数据。完成后使用-rm参数删除容器。此对备份数据已经保存在当前的目录下。示例代码如下:

#先退出容器
[root@ee9bc9586288 /]# exit
exit
#创建一个用于数据备份的容器
[root@docker _data]# docker run --rm --volumes-from data-volume -v /root/back:/backup centos tar cvf /backup/backup1.tar /var/volume1
#--rm 备份运行完,自动删除自己(数据备份服务器)
#挂载宿主机/root/backup到容器/backup
tar: Removing leading `/' from member names
/var/volume1/
/var/volume1/a.txt
[root@docker _data]# docker ps -a
#发现只有数据备份的目标容器,执行命令的容器自动删除了
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS                       PORTS     NAMES
ee9bc9586288   centos    "/bin/bash"               13 minutes ago   Exited (127) 2 minutes ago             data-volume
#文件仍然存在
[root@docker _data]# ls /root/back/
backup1.tar

管理数据卷

与容器关联

数据卷最大的优势是可以用来做持久化数据。它的生命周期是独立的,Docker

不会在容器被删除后自动删除数据卷,也不存在类似垃圾回收的机制来处理没有

被任何容器使用的数据卷。但难免会有无用的数据卷,用户可以通过在删除容器

的命令中添加参数,在删除容器的同时删除数据卷。

Docker数据卷可以通过命令与容器关联,删除容器时,数据卷也随之被删除。

  • docker rm-v

删除容器时添加-v参数会将数据卷一并删除。

  • docker run--rm

创建、运行容器时添加-rm参数,容器运行结束时容器与数据卷会被一并删除。

如果不对数据卷进行及时清理,/var/lib/docker/volumes/目录下就会产生许多残留目录。

删除的数据卷是无法找回的,建议再三确认之后再执行操作。

命令管理

Docker中有专门的容器数据卷命令供用户管理容器数据卷。下面通过示例介绍容器数据卷命的一些参数。

创建数据卷

docker volume create :创建数据卷

示例代码如下:

[root@docker _data]# docker volume create test
test
列出数据卷

docker volume ls :列出数据卷

[root@docker _data]# docker volume ls
DRIVER    VOLUME NAME
local     5e438f486323a1b43a088dae231c5936b724f9eed09334102ccf9ef0104e67c6
local     6aac0390812b71d45ac1bde6e65758215cabbd305a580d6d91963f5530905d59
local     8e2ff58f7069342ea9efdee1c335bdc7f1d9272ea1e2a14ea8da386482896f29
local     897ee8fcdbf3d866d78973d996069e8c1ea3a63f136c0e10afcbb10f099e9b16
local     8082f8bf30382b5eff4ca43d5aed94b339dc124d63739ea6fcc5f2dd3e1759f5
local     9746d50c43550621c70b69a728798eafbbfc4206e95e959ce50376df9de88347
local     a459847e1c3b220931bfefd20266c6da7fc7f148ffc2802b05e32900daafc756
local     c46e1c050f9f5820ed9d764d9e2bf291db45040c3b38f47ab7e3a92d0281f4df

也可在挂载目录查看

[root@docker _data]# ls /var/lib/docker/volumes/
5e438f486323a1b43a088dae231c5936b724f9eed09334102ccf9ef0104e67c6
6aac0390812b71d45ac1bde6e65758215cabbd305a580d6d91963f5530905d59
8082f8bf30382b5eff4ca43d5aed94b339dc124d63739ea6fcc5f2dd3e1759f5
897ee8fcdbf3d866d78973d996069e8c1ea3a63f136c0e10afcbb10f099e9b16
8e2ff58f7069342ea9efdee1c335bdc7f1d9272ea1e2a14ea8da386482896f29
9746d50c43550621c70b69a728798eafbbfc4206e95e959ce50376df9de88347
a459847e1c3b220931bfefd20266c6da7fc7f148ffc2802b05e32900daafc756
backingFsBlockDev
c46e1c050f9f5820ed9d764d9e2bf291db45040c3b38f47ab7e3a92d0281f4df
metadata.db
test
列出数据卷

docker inspect <容器id或名字>:列出数据卷

[root@docker _data]# docker inspect test
...
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/web/app",
                "Destination": "/app",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
...
删除一个或多个数据卷

docker volume rm <数据卷name>:删除一个或多个数据卷

#需要先终止并删除容器
docker stop <容器id或名字>
docker rm <容器id或名字>
#删除数据卷
docker volume rm <数据卷name>
删除所有未被使用的数据卷

docker volume prune:删除所有未被使用的数据卷

是一名喜欢每天折腾的咸鱼! 也是一名半退役的算竞摸鱼选手,参与过icpc,天梯赛,蓝桥等比赛.Datawhale 优秀队长 --------------------------------------------------- 认证类: 华为 Harmony OS应用开发者高级认证, NISP 一级认证, H3C NE-RS网络工程师认证 --------------------------------------------------- 荣获奖项荣誉: 第十八届“挑战杯”全国大学生课外学术科技作品竞赛 “揭榜挂帅”专项赛全国特等奖、 “美亚杯”第八届中国电子取证大赛 三等奖、 中国高校计算机大赛-团体程序天梯赛 省高校一等奖、 “蓝桥杯”省二等奖、 H3C新华三杯 省三等奖、 中国移动“梧桐杯”大数据创新大赛 省三等奖、 百度 飞桨领航团 金牌团长 https://pan.imgs.run/s/GQFr
最后更新于 2024-03-09