1. 什么是容器数据卷?


docker的理念回顾
将应用和环境打包成一个镜像。
数据?如果数据都在容器中,那么我们将容器删除,数据就会丢失!需求:数据可以持久化。
MySQL,容器删除了,就相当于删库跑路!需求:MySQL数据可以存储在本地!
迫切希望有一个技术:容器之间可以有一个数据共享的技术!docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!

总结:卷的技术就是为了容器的持久化和同步操纵!容器间也是可以数据共享的!

2. 使用数据卷

方式一:直接使用命令来挂载 -v

指定路径挂载

  1. docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口 镜像名称
  2. #测试
  3. docker run -it -v /home/ceshi/:/home centos /bin/bash
  4. #启动起来之后通过docker inspect 容器id 查看挂载的状况
  5. "Mounts": [
  6. {
  7. "Type": "bind",
  8. "Source": "/home/ceshi",
  9. "Destination": "/home",
  10. "Mode": "",
  11. "RW": true,
  12. "Propagation": "rprivate"
  13. }
  14. ],
  15. 在主机上touch一个新文件,在容器内也可以查看到,即使容器是关闭状态,文件依然会同步到容器内

image.png
image.png
好处:我们以后修改只需要在本地修改即可,容器内会自动同步

实战:安装 MySQL

思考MySQL的数据持久化问题

  1. #获取镜像
  2. root@kylin:/home# docker pull mysql:5.7
  3. #运行容器时做数据挂载
  4. -d 后台运行
  5. -p 端口映射
  6. -v 卷挂载
  7. -e 环境配置
  8. --name 指定名称
  9. docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d --name mysql01 mysql:5.7
  10. #启动成功后,在本地使用Mysql-Front连接远程数据库
  11. sql-front-连接到服务器的3310 --- 3310 和容器的3306 映射,这个时候就可以连接上了
  12. #在本地测试,创建一个数据库,查看一下我们映射的数据库

假设我们将容器删除,经过实践检验,我们挂载到本地的数据卷依旧没有丢失。这就实现了容器数据持久化教程。

具名挂载和匿名挂载

  • 匿名挂载 ```shell

    匿名挂载方式开启容器

    -v 容器内路径! docker run -d -P —name nginx3 -v /etc/nginx nginx

查看所有的卷(volume)的情况:

root@kylin:/home# docker volume ls DRIVER VOLUME NAME local 2d0943a371b16346b21c87357353e4a322f284e2544d1b03721c050601852692 local 09daf4be8ff4158082feded9f103173ea9cb3718aa41369769d3fa78de76b84b local 825c11e64035e76509a5ea0db6879477d022419054befd8560a159ce3478154f local 40719dd645f1369bdd96315ac23ba09414188a869ac19b3d40d3c18f20ccaf22

这里发现,这种就是匿名挂载,我们只写了容器内的路径,没有写容器外的路径

通过docker volume inspect volume_name 查看匿名卷的信息

root@kylin:/home# docker volume inspect 40719dd645f1369bdd96315ac23ba09414188a869ac19b3d40d3c18f20ccaf22 [ { “CreatedAt”: “2020-08-08T11:39:28+08:00”, “Driver”: “local”, “Labels”: null, “Mountpoint”: “/var/lib/docker/volumes/40719dd645f1369bdd96315ac23ba09414188a869ac19b3d40d3c18f20ccaf22/_data”, “Name”: “40719dd645f1369bdd96315ac23ba09414188a869ac19b3d40d3c18f20ccaf22”, “Options”: null, “Scope”: “local” } ]

  1. - 具名挂载
  2. ```shell
  3. #具名挂载方式开启容器
  4. -v 卷名:容器内路径
  5. root@kylin:/home# docker run -d -P --name nginx4 -v juming_nginx:/etc/nginx nginx
  6. #查看所有的卷
  7. root@kylin:/home# docker volume ls
  8. DRIVER VOLUME NAME
  9. local 2d0943a371b16346b21c87357353e4a322f284e2544d1b03721c050601852692
  10. local 09daf4be8ff4158082feded9f103173ea9cb3718aa41369769d3fa78de76b84b
  11. local 825c11e64035e76509a5ea0db6879477d022419054befd8560a159ce3478154f
  12. local 40719dd645f1369bdd96315ac23ba09414188a869ac19b3d40d3c18f20ccaf22
  13. local juming_nginx
  14. #查看具名挂载的卷的信息
  15. root@kylin:/home# docker volume inspect juming_nginx
  16. [
  17. {
  18. "CreatedAt": "2020-08-08T11:47:01+08:00",
  19. "Driver": "local",
  20. "Labels": null,
  21. "Mountpoint": "/var/lib/docker/volumes/juming_nginx/_data",
  22. "Name": "juming_nginx",
  23. "Options": null,
  24. "Scope": "local"
  25. }
  26. ]

所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data

我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的 具名挂载

判断 具名/匿名/指定路径 挂载

  1. #如何确定是 具名挂载 还是 匿名挂载 , 还是指定路径挂载
  2. -v 容器内路径 # 匿名挂载
  3. -v 卷名:容器内路径 # 具名挂载
  4. -v /宿主机路径:容器内路径 # 指定路径挂载

扩展:

  1. # 通过 -v 容器内路径[:ro|:rw] 改变读写权限
  2. ro readonly 只读
  3. rw readwrite 可读可写
  4. #一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
  5. docker run -d -P --name nginx4 -v juming_nginx:/etc/nginx:ro nginx
  6. docker run -d -P --name nginx4 -v juming_nginx:/etc/nginx:rw nginx
  7. #ro 只要看到这个ro,就说明这个路径只能通过宿主机改变,容器内部是无法操作的

方式二:初识Dockerfile

Dockerfile 就是用来构建 docker镜像 的构建文件!命令脚本!
先写一个dockerfile脚本,通过这个脚本可以生成一个镜像,镜像是一层层的,所以每个脚本就是一个一个的命令,每个命令都是一层!

  1. #创建一个dockerfile文件,名字可以随机,建议dockerfile
  2. #文件内容 (下面的每个命令都是镜像的一层)
  3. FROM centos
  4. VOLUME ["volume01","volume02"] //匿名方式挂载两个卷
  5. CMD echo "------end"
  6. CMD /bin/bash
  7. #执行构建命令
  8. 注意最后面有个点,并且镜像名的最前面不能有"/"
  9. docker build -f dockerfile1 -t kylin/centos .
  10. #结果显示
  11. root@kylin:/home/docker_volume_test# docker build -f dockerfile1 -t kylin/centos .
  12. Sending build context to Docker daemon 2.048kB
  13. Step 1/4 : FROM centos
  14. ---> 831691599b88
  15. Step 2/4 : VOLUME ["volume01","volume02"]
  16. ---> Running in ee6ff7b33bbf
  17. Removing intermediate container ee6ff7b33bbf
  18. ---> 778da48c9617
  19. Step 3/4 : CMD echo "------end"
  20. ---> Running in 5346f74b5915
  21. Removing intermediate container 5346f74b5915
  22. ---> 5812457cde63
  23. Step 4/4 : CMD /bin/bash
  24. ---> Running in c42e0db993d9
  25. Removing intermediate container c42e0db993d9
  26. ---> fb7d10d0b5d6
  27. Successfully built fb7d10d0b5d6
  28. Successfully tagged kylin/centos:latest

image.png

  • 启动自己写的容器

image.png
注意看,最下面有两个卷,那就是我们自己挂载的。
这个卷和外部一定有一个同步的目录,通过 docker inspect 容器id 查看挂载的卷在本地什么位置
我们在容器中的volume01中写一个文件container.txt,然后在宿主机的相应位置查看一下:

  1. "Mounts": [
  2. {
  3. "Type": "volume",
  4. "Name": "9e316914bbd76835e86062950702ce71c8cac3f631fbe0bcbe1a31e2fe047193",
  5. "Source": "/var/lib/docker/volumes/9e316914bbd76835e86062950702ce71c8cac3f631fbe0bcbe1a31e2fe047193/_data",
  6. "Destination": "volume02",
  7. "Driver": "local",
  8. "Mode": "",
  9. "RW": true,
  10. "Propagation": ""
  11. },
  12. {
  13. "Type": "volume",
  14. "Name": "a7bad1d08e0f226fbaededce48798cf6f114076dfcf955639687c0a3bfeb7c75",
  15. "Source": "/var/lib/docker/volumes/a7bad1d08e0f226fbaededce48798cf6f114076dfcf955639687c0a3bfeb7c75/_data",
  16. "Destination": "volume01",
  17. "Driver": "local",
  18. "Mode": "",
  19. "RW": true,
  20. "Propagation": ""
  21. }
  22. ],

在宿主机进入volume01相对应的目录,然后查看
image.png
这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!
假设构建镜像的时候没有挂载卷,要手动镜像挂载: -v 卷名:容器内路径 !

3. 数据卷容器

开启容器1: docker01

  1. #开启容器01
  2. docker run -it --name docker01 kylin/centos

image.png

开启容器2: docker02

(注意:使用 —volumes-from docker01 继承 docker01 的 volumes )

  1. docker run -it --name docker02 --volumes-from docker01 kylin/centos

成功开启之后,在docker01的volume01目录创建一个名为docker01的文件,然后在docker02容器上能够看见。
image.png

开启容器3: docker03

(注意:使用 —volumes-from docker01 继承 docker01 的 volumes )
在容器3的volumes01目录下,创建一个名为docker03的文件,可以在docker01上看到同步的。
image.png
只要通过 --volumes-from (父)容器id ,就可以直接继承docker01的数据卷,实现数据同步。

虽然说是从docker01继承的,但其实是三个容器的数据卷相互同步。即使删除了docker01,docker02和docker03的数据也依然是存在的。
通过 docker inspect 查看每个容器的挂载信息,可以看见,他们三个容器都使用了同一个卷!!同一个卷!!

  1. "Mounts": [
  2. {
  3. "Type": "volume",
  4. "Name": "a89459225362be0282cce4137f9a1ef0a73bc4e7a046e985b2ba1ff033e30a35",
  5. "Source": "/var/lib/docker/volumes/a89459225362be0282cce4137f9a1ef0a73bc4e7a046e985b2ba1ff033e30a35/_data",
  6. "Destination": "volume02",
  7. "Driver": "local",
  8. "Mode": "",
  9. "RW": true,
  10. "Propagation": ""
  11. },
  12. {
  13. "Type": "volume",
  14. "Name": "676a0154ce4061f2922f9aec948672dfdf878ab1e514760e60cc15c35006da7c",
  15. "Source": "/var/lib/docker/volumes/676a0154ce4061f2922f9aec948672dfdf878ab1e514760e60cc15c35006da7c/_data",
  16. "Destination": "volume01",
  17. "Driver": "local",
  18. "Mode": "",
  19. "RW": true,
  20. "Propagation": ""
  21. }
  22. ],

作业:多个MySQL 实现数据共享
注意:

  • mysql01 绑定了3310端口,那么mysql02就应该换一个其他的端口(3311)
  • mysql02 直接通过 --volumes-from mysql01 使用 mysql01 的数据卷即可 ```shell docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d —name mysql01 mysql:5.7

docker run -d -p 3311:3306 —volumes-from mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d —name mysql02 mysql:5.7 ```

结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的