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 成为其子级 那么 三个容器间 与宿主机则相互串起来了了 数据达到了同步到效果
总结
学习之路不易 长路漫漫 要学习的东西还是很多