一、什么是容器数据卷
docker 的理念回顾:
将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够持久化的!就好比,你安装一个 MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!
所以我们希望容器之间有可能可以共享数据,Docker 容器产生的数据,如果不通过 Docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行不通的!
为了能保存数据在 Docker 中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除而丢失了!
作用:
卷就是目录或者文件,存在一个或者多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂载的数据卷。
特点:
1、数据卷可在容器之间共享或重用数据
2、卷中的更改可以直接生效
3、数据卷中的更改不会包含在镜像的更新中
4、数据卷的生命周期一直持续到没有容器使用它为止
二、使用数据卷
容器中直接使用命令来添加
1、启动容器并挂载
# 命令
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
# 测试
[root@localhost home]# docker run -it -v /home/ceshi:/home centos /bin/bash
# 查看数据卷是否挂载成功
docker inspect 容器id
2、测试容器和宿主机之间数据共享,可以发现,在容器中创建的文件会在宿主机中看到。
3、测试容器停止退出后,主机修改数据是否会同步
# 1、停止容器
# 2、在宿主机修改文件,增加些内容
# 3、启动刚才的容器
# 4、查看对应的文件是否发生变化,结果是发生了变化
使用 docker 安装 mysql
# 1、搜索镜像
[root@localhost home]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 14320 [OK]
# 2、拉取镜像
[root@localhost home]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Pull complete
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
# 3、启动容器 -e 环境变量!mysql 的数据应该不丢失!先体验下 -v 挂载卷! 参考官方文档
[root@localhost home]# docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
b6a5895fbab7a5acfd332bf8b2f2f541e6fbff5d425a597983b7877ae7641c60
# 4、使用本地的数据库连接工具连接测试一下,并创建一个数据库 test
# 5、查看本地的 /home/mysql 目录,可以看到我们刚刚建立的 test 数据库在本地存储着
[root@localhost home]# cd /home/mysql/data/
[root@localhost data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem test
# 6、删除 mysql 容器,然后发现远程连接失败!可以看到我们刚刚建立的 test 数据库还在本地存储着
[root@localhost data]# docker rm -f mysql01
mysql01
[root@localhost data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem test
使用 DockerFile 来添加数据卷
DockerFile 是用来构建 Docker 镜像的构建文件,是由一些列命令和参数构成的脚本。我们在这里先体验下,后面我们会详细讲解 DockerFile !
# 1、我们在宿主机 /home 目录下新建一个 docker_volume_test 文件夹
[root@localhost home]# mkdir docker_volume_test
# 说明:在编写 DockerFile 文件中使用 VOLUME 指令来给镜像添加一个或多个数据卷
# 例如:VOLUME["/dataVolume1","/dataVolume2","/dataVolume3"]
# 出于可移植和分享的考虑,我们之前使用的 -v 主机目录:容器目录 这种方式不能够直接在 DockerFile 中实现。因为宿主机目录是依赖于特定宿主机的,并不能够保证在所有宿主机上都存在这样的特定目录
# 2、编写 DockerFile 文件
[root@localhost docker_volume_test]# pwd
/home/docker_volume_test
[root@localhost docker_volume_test]# vim dockerfile
[root@localhost docker_volume_test]# cat dockerfile
FROM centos
VOLUME ["dataVolume1","dataVolume2"]
CMD echo "------end-----"
CMD /bin/bash
# 3、build 后生成镜像,获得一个新镜像 xhf_centos
# 注意最后有个.
[root@localhost docker_volume_test]# docker build -f /home/docker_volume_test/dockerfile -t xhf_centos .
[+] Building 0.5s (5/5) FINISHED docker:default
=> [internal] load .dockerignore 0.2s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from dockerfile 0.2s
=> => transferring dockerfile: 185B 0.1s
=> [internal] load metadata for docker.io/library/centos:latest 0.0s
=> [1/1] FROM docker.io/library/centos 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:9a63d60a258f85e3bfe65ad6c8ac1e53a280fae5356f1bcec650bfa66e919989 0.0s
=> => naming to docker.io/library/xhf_centos
# 查看我们生成的镜像
[root@localhost docker_volume_test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
xhf_centos latest 9a63d60a258f 22 months ago 231MB
centos latest 5d0da3dc9764 22 months ago 231MB
# 4、启动容器
[root@localhost docker_volume_test]# docker run -it 9a63d60a258f /bin/bash
[root@0f3404705e21 /]# ls -l
total 0
lrwxrwxrwx. 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x. 2 root root 6 Jul 19 07:47 dataVolume1 # 数据卷目录
drwxr-xr-x. 2 root root 6 Jul 19 07:47 dataVolume2 # 数据卷目录
drwxr-xr-x. 5 root root 360 Jul 19 07:47 dev
drwxr-xr-x. 1 root root 66 Jul 19 07:47 etc
drwxr-xr-x. 2 root root 6 Nov 3 2020 home
lrwxrwxrwx. 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------. 2 root root 6 Sep 15 2021 lost+found
drwxr-xr-x. 2 root root 6 Nov 3 2020 media
drwxr-xr-x. 2 root root 6 Nov 3 2020 mnt
drwxr-xr-x. 2 root root 6 Nov 3 2020 opt
dr-xr-xr-x. 257 root root 0 Jul 19 07:47 proc
dr-xr-x---. 2 root root 162 Sep 15 2021 root
drwxr-xr-x. 11 root root 163 Sep 15 2021 run
lrwxrwxrwx. 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Nov 3 2020 srv
dr-xr-xr-x. 13 root root 0 Jul 12 07:05 sys
drwxrwxrwt. 7 root root 171 Sep 15 2021 tmp
drwxr-xr-x. 12 root root 144 Sep 15 2021 usr
drwxr-xr-x. 20 root root 262 Sep 15 2021 var
# 问题:通过上述步骤,容器内的卷目录地址就已经知道了,但是对应的主机目录地址在哪里呢?
# 5、我们在数据卷中新建一个文件
[root@0f3404705e21 dataVolume1]# pwd
/dataVolume1
[root@0f3404705e21 dataVolume1]# touch dataTest.java
[root@0f3404705e21 dataVolume1]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 07:50 dataTest.java
# 6、查看下这个容器的信息
[root@localhost ~]# docker inspect 0f3404705e21
// ......
"Mounts": [
{
"Type": "volume",
"Name": "fdd0a9596867bda543cefd22df9632cef624c9bfa6ffe9daa13fd042b0d98aee",
"Source": "/var/lib/docker/volumes/fdd0a9596867bda543cefd22df9632cef624c9bfa6ffe9daa13fd042b0d98aee/_data",
"Destination": "dataVolume1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "0fe1ff905e66aef43d7db6502fd5d98e9cf67ca83c8c1ab6614fe72da2ea84cd",
"Source": "/var/lib/docker/volumes/0fe1ff905e66aef43d7db6502fd5d98e9cf67ca83c8c1ab6614fe72da2ea84cd/_data",
"Destination": "dataVolume2",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
// ........
# 7、查看我们刚才创建的文件信息
[root@localhost ~]# cd /var/lib/docker/volumes/fdd0a9596867bda543cefd22df9632cef624c9bfa6ffe9daa13fd042b0d98aee/_data
[root@localhost _data]# ls
dataTest.java
[root@localhost _data]#
三、匿名和具名挂载
# 匿名挂载
# -v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 匿名挂载的缺点,就是不好维护,通常使用命令 docker volume 维护
docker volume ls
# 具名挂载
# -v 卷名:/容器内路径
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
# 查看挂载的路径
[root@localhost data]# docker volume inspect nginxconfig
[
{
"CreatedAt": "2023-07-18T02:13:38-07:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginxconfig/_data",
"Name": "nginxconfig",
"Options": null,
"Scope": "local"
}
]
# 怎么判断挂载的是卷名而不是本机目录名?
# 不是 / 开始就是卷名,是 / 开始就是目录名
# 改变文件的读写权限
# ro: readonly
# rw: readwrite
# 指定容器对我们挂载出来的内容的读写权限
docker run -d -P --name nginx03 -v nginxconfig:/etc/nginx:ro nginx
docker run -d -P --name nginx04 -v nginxconfig:/etc/nginx:rw nginx
四、数据卷容器
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器。
我们使用上一步自定义的镜像:xhf_centos 为模板,并运行容器 docker01,docker02,docker03,因为他们都默认具有容器卷。
1、先启动一个父容器 docker01,然后在 dataVolume1 中新增文件 docker01.txt,如下所示:
退出不停止:ctrl+P+Q
2、创建 docker02 和 docker03 让他们都继承 docker01,使用 --volumes-from 标签
# 启动 docker02
[root@621e0c81ba67 dataVolume2]# [root@localhost ceshi]# docker run -it --name docker02 --volumes-from docker01 xhf_centos
[root@85789dab892c /]# cd /dataVolume2
[root@85789dab892c dataVolume2]# ls
docker01.txt
[root@85789dab892c dataVolume2]# touch docker02.txt
[root@85789dab892c dataVolume2]# ls
docker01.txt docker02.txt
# 启动 docker03
[root@85789dab892c dataVolume2]# [root@localhost ceshi]# docker run -it --name docker03 --volumes-from docker01 xhf_centos
[root@35d6d33de63c /]# cd /dataVolume2
[root@35d6d33de63c dataVolume2]# ls
docker01.txt docker02.txt
[root@35d6d33de63c dataVolume2]# touch docker03.txt
[root@35d6d33de63c dataVolume2]# ls
docker01.txt docker02.txt docker03.txt
3、回到 docker01 发现可以看到 docker02 和 docker03 添加的文件。
[root@localhost ~]# docker attach docker01
[root@621e0c81ba67 dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
4、删除 docker01 容器并且在 docker02 容器添加文件,然后看 docker03 容器还能不能访问。
[root@localhost ~]# docker rm -f docker01
docker01
[root@localhost ~]# docker attach docker02
[root@85789dab892c dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
[root@85789dab892c dataVolume2]# touch docker02-update.txt
[root@85789dab892c dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:15 docker02-update.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
# 此时已经切换到 docker03 容器了,使用ctrl+p+q
[root@35d6d33de63c dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:15 docker02-update.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
5、删除 docker02 ,测试 docker03 还能不能访问。答案是可以访问的。
[root@localhost ~]# docker rm -f docker02
docker02
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
35d6d33de63c xhf_centos "/bin/sh -c /bin/bash" 9 minutes ago Up 9 minutes docker03
[root@localhost ~]# docker attach docker03
[root@35d6d33de63c dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:15 docker02-update.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
[root@35d6d33de63c dataVolume2]# touch docker03_update.txt
6、新建 docker04 继承 docker03,然后再删除 docker03,看下是否可以访问!
[root@localhost ~]# docker run -it --name docker04 --volumes-from docker03 xhf_centos
[root@fd19bc431b37 /]# cd /dataVolume2
[root@fd19bc431b37 dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:15 docker02-update.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
-rw-r--r--. 1 root root 0 Jul 19 08:19 docker03_update.txt
# 切换目录 ctrl+p+q
[root@localhost ~]# docker rm -f docker03
docker03
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fd19bc431b37 xhf_centos "/bin/sh -c /bin/bash" About a minute ago Up About a minute docker04
[root@localhost ~]# docker attach docker04
[root@fd19bc431b37 dataVolume2]# ls -l
total 0
-rw-r--r--. 1 root root 0 Jul 19 08:05 docker01.txt
-rw-r--r--. 1 root root 0 Jul 19 08:15 docker02-update.txt
-rw-r--r--. 1 root root 0 Jul 19 08:08 docker02.txt
-rw-r--r--. 1 root root 0 Jul 19 08:09 docker03.txt
-rw-r--r--. 1 root root 0 Jul 19 08:19 docker03_update.txt
结论:
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。存储在本机的文件则会一直保留!