Docker 文件分层及数据挂载

本文为转载 : 原文地址

前言

书接上回,之前我们说到了docker文件的基本命令,那么在我们实际操作当中,离不开数据源的处理,那么有人会说了,我直接将docker容器删除了,那我的数据岂不是就没了?我的docker容器损坏了,那我的数据不也是没了?

那我们如何保证在docker容器损坏的情况下保存数据呢? 那就是今天的主题了,docker文件的分级以及挂载,这个能够有效的保证我们的数据文件存放在宿主机,docker容器也能够访问宿主机的数据,从而导致删除容器只要新建一个容器,指定文件路径就可以重新使用该容器.

1.数据分层

之前拉取mysql镜像文件的时候其实有个小小的问题.

看图:

这里会发现,有些数据文件已经在上一次拉取的存在了.然后才去拉取mysql其他的文件
在这里插入图片描述

其实,我们通过上一章节的学习,拉取了许许多多镜像后.终于发现 无论什么镜像 在下载的时候 都不是一个下载进度条 都是多层 多个进度条下载,有的会提示 Already exists 好像一个镜像被拆分成了多层宝塔一般同时分层下载。

当然这里只是说一下我个人的见解: 这种分层技术是docker强大的功能点之一,会减少很多冗余的文件,每一个镜像设置为宝塔形(象征意义可以理解为金字塔一样),进行分层。当某一个镜像文件依赖于另一个镜像文件的分层时。会先去判断当前文件是否自身已经下载过,如果存在那么久不下载,仅仅只下载当前需要的文件。

也可以理解为盖楼房,楼房一层层往上建起来,那么上次文件就是依赖下层文件,当我们删除docker镜像的时候,它也会查看自己构成镜像的所有曾,如果自己的某一层及被另一个镜像依赖(或者正在使用)那么就会忽略删除该层级。

就比如上面图示,我们下载mysql的时候可以依赖于某个文件,那么在第一次pull mysql的时候会判断当前docker是否含有这个镜像文件的分层。如果存在的话就不会下载,继续下载mysql需要的镜像文件。然后一层一层下载完成之后就组成一个完整的mysql镜像文件了。

但我们再次下载mysql:5.7.30时,可能会跟mysql已经下载的部分文件重叠,那么这个时候mysql:5.7.30就不会下载重复文件,就会下载它自身需要的其他文件。所以这也是为什么会出现 Already exists 的原因。

数据分层总结

下载镜像文件会检查当前docker内是否存在相同的依赖文件,如果存在则不下载相同的依赖文件,则去下载其他必要文件,这也是为什么推崇docker的一个方面。能够节省一些服务器资源,减少冗余资源。

2.数据卷的使用

如何正确的使用挂载数据

数据卷的概念

docker容器虽然好用,但是我们会在使用的过程中发现一些问题,下面列举几个场景供大家学习。

场景一:

需求: 需要容器数据持久化或绑定到外部宿主机

例:我在安装了mysql并把mysql作为数据源在项目当中使用,那么当我们不想使用这个容器,或者这个容器出现问题需要删除时,是不是就把容器当中的数据删除了?

场景二:

需求: 外部修改文件内容,需要同步到容器内部,类似于宿主机与容器间的端口映射

通过上一章节内容了解过了,容器内是无法使用linux命令的,例如ll、vim、vi等,那么我们修改一些配置文件时就很不方便,比如修改我们的profile配置文件,还需要在当前容器内下载vim插件。那么这样每个容器都要下载,而且下载速度非常缓慢,这样肯定是不行的。

那我们如果将宿主机中的某个目录,映射到容器中,这样在容器中的目录下修改文件,即使容器关闭,数据也会相应的保留下来,供宿主机和其他容器访问。

数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:

- 数据卷可以在容器之间共享和重用

- 对数据卷的修改会立马生效

- 对数据卷的更新,不会影响镜像

- 卷会一直存在,直到没有容器使用

数据卷的简单使用

在我们 run 运行镜像的时候 可以使用 -v 参数来实现宿主目录与虚拟机目录进行挂在映射

例如启动一个redis镜像 设置端口映射 别名为redis01

docker run -d -p 6379:6379 --name redis01 -v /tmp/redis_test/data:/tmp/redis_test/data redis

-d 后台运行容器,并返回容器ID
-p 6379:6379 指定端口映射,格式:主机(宿主)端口:容器端口
–name 指定容器名称 调用容器时只需输入redis01既可
-v /tmp/redis_test/data:/tmp/redis_test/data 映射数据目录(将宿主机目录映射到容器当中)
redis 镜像文件名称

在这里插入图片描述
现在就可以发现,我们已经将宿主机的目录挂载起来了

那我们来进行一个小实验,测试一下,我们在宿主机创建一个新文件,查看容器内部是否会更新。

  • 在宿主机新增文件,容器内是否新增

显而易见的是文件会更新到容器内部,那么容器内部创建新的文件,宿主机会更新吗?
在这里插入图片描述

  • 在容器内部新增文件,查看宿主机是否新增

在容器内部新增一个文件夹,然后去宿主机目录查看是否新增
在这里插入图片描述

  • 关闭容器,在宿主机新增文件,再查看容器内文件是否新增

在这里插入图片描述

3.数据卷闭坑指南

可以从上面的例子知道,在挂载数据之后,新增数据是同步的,那么删除数据是否也是同步的呢?

场景三:

验证mysql数据挂载同步操作

不管是在日常的测试还是开发过程中,数据库存储数据是缺少不了的,为了加深我们的印象,来模拟一下同步容器以及删除容器。好让咱们自己意识到到底如何保存数据!

配置mysql容器

先拉去mysql的镜像文件

docker pull mysql:5.7.30

再进行持久化运行,指定端口,数据卷挂在再设置密码启动

只是我们按照之前配置redis的命令运行,发现这容器好像没有运行起来,这是为什么?
在这里插入图片描述
尝试进入容器内部,发现报错说容器当前未在运行状态

docker exec -it mysql01 bash

在这里插入图片描述
这里我们查看容器日志,了解具体的情况

docker logs mysql01

如图所知,我们需要提供mysql的管理员账号以及其他确认密码
在这里插入图片描述

参数说明:

  • MYSQL_ROOT_PASSWORD --用户密码
  • MYSQL_ALLOW_EMPTY_PASSWORD --这是一个可选变量。设置为非空值,例如yes,以允许使用 root 用户的空白密码启动容器。注意:除非您真的知道自己在做什么,否则不建议将此变量设置yes为,因为这将使您的 MySQL 实例完全不受保护,从而允许任何人获得完全的超级用户访问权限。
  • MYSQL_RANDOM_ROOT_PASSWORD – 这是一个可选变量。设置为非空值,例如yes,为 root 用户生成一个随机初始密码(使用pwgen)。生成的 root 密码将打印到 stdout ( GENERATED ROOT PASSWORD: …)。

查看mysql官方文档,这里有详细描写如何启动一个实例

官方文档地址: Mysql-docker实例配置

在这里插入图片描述

往文档下面翻,我们既然要挂载数据那么肯定要弄清楚mysql挂载数据的正确姿势,那我们看到存储数据

配置文件路径在 /etc/mysql/conf.d 数据存储路径在/var/lib/mysql
在这里插入图片描述

那么我们配置mysql容器的启动命令需要调整为

docker run -d -p 3306:3306 --name mysql01 -v /tmp/mysql_test/conf:/etc/mysql/conf.d -v /tmp/mysql_test/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql

参数说明:

  • /tmp/mysql_test/conf:/etc/mysql/conf.d 这是mysql指定配置文件挂载目录
  • /tmp/mysql_test/data:/var/lib/mysql 这是mysql数据存储路径
  • MYSQL_ROOT_PASSWORD root用户登录的密码

这里可以看到我们的mysql容器当前正在运行,我们用Navcat测试连接一下
在这里插入图片描述

连接成功.
在这里插入图片描述

测试容器内外数据同步性

然后再看我们挂载的 /tmp/mysql_test/data 下是否有容器中的文件,果然是有的
在这里插入图片描述

咱们使用Navicat创建一个新的数据库,并且在数据库中穿点一张表并插入一条数据

然后到挂载的宿主机目录及容器中查看

  • 宿主机的挂载目录
    在这里插入图片描述
  • 容器内挂载目录
# 进入容器
docker exec -it mysql01 bash
# 进入挂载数据目录
cd /var/lib/mysql
# 进入新增数据库
cd test_mysql

在这里插入图片描述

删除容器内部数据,测试同步性

为了更好的测试数据同步性,我们将容器内部 test_mysql 库给他删除

在这里插入图片描述

删除之后,我们进行查看数据库,会发现当前数据库已经不存在.在这里插入图片描述

查看挂载目录是否还存在该数据库,由下图可见,在容器内外部都没有发现 test_mysql数据库了

  • 宿主机挂载目录

在这里插入图片描述

  • 容器内部挂载目录

在这里插入图片描述

那么咱们一直说的 数据持久化 到底是什么呢?

容器中 新增数据–同步到了宿主机
容器中 删除目录–同步到了宿主机

删除容器是否会影响数据?

带着咱们的疑问进行最后一个验证

向容器中添加数据后,删除容器,然后在运行一个全新的容器示例,将其数据绑定到上一个容器数据目录,查看数据是否会被丢失

  • 1.在当前容器添加数据

新增learn库,新增student表,并插入数据

在这里插入图片描述

  • 2.删除mysql01容器

先将容器停止运行,然后在删除容器
在这里插入图片描述

  • 3.创建新的容器示例, 与之前Mysql容器绑定
docker run -d -p 3306:3306 --name mysql01 -v /tmp/mysql_test/conf:/etc/mysql/conf.d -v /tmp/mysql_test/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql

在这里插入图片描述

  • 4.查看我们的数据之前数据库的数据

在这里插入图片描述
哦豁,在这儿我们发现,删除容器并不会影响我们的数据。那么我们至少可以得出两个结论

闭坑小结

容器内新建、删除、修改文件会同步到宿主机外部挂在目录 !!!

容器整个删除:宿主机外部挂在目录不会同步!!!

4.数据卷挂载之匿名挂载

我们上面使用的挂载是 -v 接具体的挂载路径,这很明确的指定了容器目录,挂载到宿主机的位置

首先我们可以查看所有挂在卷的列表

docker volume ls 

在这里插入图片描述

像当前这个列表,展示出的所有卷都是匿名挂载,并且volume name 是一串随机的编码,直观上看,不知道具体的名字以及文件挂在到宿主机的路径

我们用-v命令进行挂在的时候,仅仅指定容器内部挂在路径,不指定外部这种命令挂载的卷,都是匿名挂载

# -v 后面未制定宿主局的路径一级挂载名
docker run -d -v /data redis

在这里插入图片描述

5.数据挂载之具名挂载

上面说到了匿名挂载,接下来我们说说具名挂载,那么什么是具名挂载呢

概念:
即在容器与宿主机进行挂载的时候制定一个名字

# -v 后面 指定挂载的卷名:/容器内路径
docker run -d -v names:/data --name jumingguazai redis

在这里插入图片描述

那我们怎么查看卷所在的宿主机位置呢

  • 查看挂在卷所在宿主机位置
docker volume inspect names

在这里插入图片描述

  • 未指定挂载目录

我们在挂载的时候 如果没有指定目录,都会默认挂载到 /var/lib/docker/volumes

在这里插入图片描述

在官网 查看 挂载的 时候 发现 挂载 路径后 还可以添加 :ro 或者 :rw 其实这两个 代表中数据卷 在容器目录中的操作权限

ro: read only 尽可读 容器中 不能在 数据卷挂载目录 进行写入 仅可在宿主机上操作

**rw:read write 可读可写 ** 宿主机 容器中 均可操作 数据卷挂载所在目录

使用示例:

docker run -d -v /docker/redis:/data:rw  --name redisrotest  redis

我们挂载的时候 不写 其实默认的是使用了 rw 权限 可读 可写

6.容器间的数据共享

我们之前已经学习过用 -v 指定路径挂载容器与宿主机之前进行了数据同步,那么现在说说容器与容器之间使用数据卷进行数据同步

使用之前的容器

  • 查看容器的详细信息
# 语法
docker inspect 容器ID/容器名
# 查看jumingguazai容器的详细信息
docker inspect redisrotest

在这里插入图片描述

发现容器内部的 /data 与宿主机的 /docker/redis 挂载的

容器之间 使用数据卷挂载命令 --volumes-from 要挂载容器ID

docker run -it --name redis02 --volumes-from redisrotest redis /bin/bash

在这里插入图片描述

这个时候 容器一 就相当于是 容器二的父容器

我们还可以再创建一个容器redis03 使其成为容器二的子级容器

docker run -it --volumes-from redis02 --name redis03 redis /bin/bash

在这里插入图片描述

几幅图 可以看出 我创建了 redisrotest (容器一) 然后 通过redis 镜像 构建容器二(redis02) 并使用 --volumes-from 绑定到容器一 那么此时 redisrotest 则为 redis02的父级容器 由于数据卷的缘故 他们数据是相互同步的,且同步到宿主机 ,然后呢我又创建了一个容器三(redis03)使redis02 成为其子级 那么 三个容器间 与宿主机则相互串起来了了 数据达到了同步到效果

在这里插入图片描述

总结

学习之路不易 长路漫漫 要学习的东西还是很多

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罐装七喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值