存储卷
- 什么是存储卷
- 为什么需要存储卷
- 存储卷分类
- volume操作命令
-
- [docker volume create](#docker volume create)
- [docker volume inspect](#docker volume inspect)
- [docker volume ls](#docker volume ls)
- [dokcer volume rm](#dokcer volume rm)
- [docker volune prune](#docker volune prune)
- [volume docker(管理卷)](#volume docker(管理卷))
- [bind mount(绑定卷)](#bind mount(绑定卷))
- [tmpfs mount(临时数据卷)](#tmpfs mount(临时数据卷))
- 总结
- 综合实战-MySQL灾难恢复
- 常见问题
什么是存储卷
存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。在宿主机上的这个与容器形成绑定关系的目录被称作存储卷。卷的本质是文件或者目录,它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。宿主机的/data/web 目录与容器中的/container/data/web 目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器写入内容,容器和宿主机的数据读写是同步的。
为什么需要存储卷
- 数据丢失问题
容器按照业务类型,总体可以分为两类:
•无状态的(数据不需要被持久化)
•有状态的(数据需要被持久化)
显然,容器更擅长无状态应用。因为未持久化数据的容器根目录的生命周期与容器的
生命周期一样,容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对
任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。
虽然容器希望所有的业务都尽量保持无状态,这样容器就可以开箱即用,并且可以任
意调度,但实际业务总是有各种需要数据持久化的场景,比如 MySQL、Kafka 等有状
态的业务。因此为了解决有状态业务的需求,Docker 提出了卷(Volume)的概念。
- 性能问题
UnionFS 对于修改删除等,一般效率非常低,如果对一于 I/O 要求比较高的应用,如redis 在实现持化存储时,是在底层存储时的性能要求比较高;
- 宿主机和容器互访不方便
宿主机访问容器,或者容器访问要通过 docker cp 来完成,应用很难操作
- 容器和容器共享不方便
存储卷分类
- volume docker 管理卷: 默认映射到宿主机的/var/lib/docker/volumes/目录下,只需要在容器内部指定挂载点是什么即可,而被绑定宿主机下的那个目录,有docker引擎daemon自行在/var/lib/docker/volumes/目录下创建一个空目录,或者使用一个已经存在的目录,与容器的挂载点建立绑定关系,这种方式极大的解脱用户在使用卷时的耦合关系,缺陷是用户无法自己指定宿主机上的目录,临时存储比较适合;
- bind mount绑定数据卷: 宿主机上的目录可以由用户自行指定,容器中的目录也可以由用户自行指定;
- tmpfs mount临时数据卷: 映射到宿主机内存,一旦容器停止运行,tmpfs mounts会被移除,数据就会丢失,用于高性能的临时数据存储;
volume操作命令
docker volume create
语法 : docker volume create [OPYIONS] [VOLUME]
功能 :创建一个存储卷(管理卷类型),如果没有指定卷的名字,则由docker 引擎自动生成,否则则使用指定的;
参数 :
--label: 指定一些元数据
-d: 指定驱动,默认时local,一般情况不需要更改;
实战 :
docker volume inspect
语法 :docker volume inspect [OPTIONS] VOLUME [VOLUME...]
功能 :查看一个或多个存储卷的详细信息;
实战 :
docker volume ls
语法 :docker volume ls [OPTIONS]
别名 :docker volume list
功能 :列出所有docker已知的存储卷
实战 :
dokcer volume rm
语法 :docker volume rm [OPTIONS] VOLUME [VOLUME...]
别名 :docker volume remove
功能 :删除一个或多个存储卷
参数 :
-f: 强制删除
实战 :
docker volune prune
语法 :docker volume prune [OPTIONS]
功能 : 删除未被使用的存储卷;
参数 :
-a:删除所有存储卷
-f: 不需要提示消息;
实战 :
volume docker(管理卷)
- 使用docker volume create 创建testVolume1管理卷
开始管理卷和容器目录的绑定工作---方式1:
- docker run -v [宿主机目录:容器目录]
- 紧接着,我们试着修改一下index.html中的内容,看看会不会影响容器中的nginx的页面显示:
- 访问一下nginx服务:
开始管理卷和容器目录的绑定工作---方式2:
docker run --mount 'key1=val1,key2=val2...'
其中key的参数有:
type: 卷的类型,目前只有volume 、bind、tmpfs
src: 对于命名卷,这是卷的名称;对于匿名卷,则省略这部分;
dst: 文件或目录挂载在容器中的路径;
ro: readonly,以只读方式挂载,改权限限于容器内部;使用--mount选项来挂载一个命名管理卷:
总结创建volume卷的方法:docker volume create xxx;
docker run -v xxxx:/containerPath/ ,如果xxxx管理卷不存在,那么docker run在启动的时候会自动创建,然后完成绑定;
docker run --mount 'type=volume,src=xxxx,dst=/ContainerPath/',如果xxxx管理卷不存在,那么docker run在启动容器的时候就会创建它,然后完成绑定;
bind mount(绑定卷)
方式1: 使用-v 来绑定容器目录:
方式2:使用--mount 来绑定
tmpfs mount(临时数据卷)
方式1:使用--tmpfs 来创建
方式2: --mount方式创建:
总结
对于管理卷来说:
如果宿主机的目录没有文件时,那么在与容器的目录绑定过后的情况取决于容器的目录;
如果宿主机中的目录有文件时,那么与容器的目录绑定过后的情况取决于宿主机的目录;
对于-v选项来说,如果管理卷不存在,则会创建;
对于--mount选项来说,如果管理卷不存在,则会创建;
不同容器之间可以共享同一个管理卷;
生命周期不随容器;
对于bind卷来说:如果宿主机的目录没有文件时,那么与容器的目录绑定过后的情况取决与宿主机的目录;
如果宿主机中的目录有文件时,那么与容器的目录绑定过后的情况取决于宿主机的目录;
对于-v选项来说,如果宿主机目录不存在,则会创建;
对于--mount选项来说,如果宿主机目录不存在,则会报错;
不同容器之间可以共享同一个bind卷;
生命周期不随容器;
对于tmpfs卷来说:指定的容器内的路径不存在时,则创建;
指定的容器内的路径下包含文件的时候,会被清空;
tmpfs卷不可被容器共享;
指定的容器内的路径必须以绝对路径的形式指定;
tmpfs卷生命周期随容器;
综合实战-MySQL灾难恢复
实验步骤:
使用mysql镜像启动一个mysql容器,并创建一个bind卷与mysql的数据管理目录进行绑定,之后我们登录容器内部的mysql服务,创建一个数据库,并创建一个 表,在表中插入一些数据,之后我们强行杀掉容器,再启动一个新的mysql容器,并将这个新的mysql容器的数据目录与刚才的卷绑定在一起,通过这个新的mysql容器看看之前的数据是否恢复;
- 准备mysql镜像:
- 启动mysql镜像,并完成卷的绑定:
- 使用docker exec登录mysql容器;
- 在这个mysql容器内创建新数据库和新表,并插入数据:
- 在宿主机上查看情况:
- 外部直接暴力删除容器:
- 再启动一个新mysql服务,并且将此时的卷绑定上去:
- 重新登录这个新的mysql2容器:
常见问题
什么时候用 Volume,什么时候用 bind、tmpfs?
- volume:volume 是 docker 的宿主机文件系统一部分,用于不需要规划具体目录的场景;
- bind:bind mount 完全是依赖于主机的目录结构和操作系统,用于目录需要提前规划,比如 mysql 的目录需要个空间大的,其他服务有不占用的时候,用 volume 就不太合适了;
- tmpfs:用于敏感文件存储,文件不想存储的宿主机和容器的可写层之中;