一、认识
1.1 概念
存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这意味着,在容器中的这个目录下写入数据时,容器会将内容直接写入到宿主机上与此容器建立了绑定关系的目录
在宿主机上的这个与容器形成绑定关系的目录被称为存储卷。卷的本质是文件或者目录,其可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上
若宿主机的 /data/web 目录与容器中的 /container/data/web 目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以由宿主机向容器写入内容,容器和宿主机的数据读写是同步的
1.2 作用
数据丢失问题
容器按照业务类型,总体可以分为两类:
- 无状态的(数据不需要被持久化)
- 有状态的(数据需要被持久化)
容器更擅长无状态应用。因为未持久化数据的容器根目录的生命周期与容器的生命周期一样,容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。
虽然容器希望所有的业务都尽量保持无状态,这样容器就可以开箱即用,并且可以任意调度,但实际业务总是有各种需要数据持久化的场景,如 MySQL、Kafka 等有状态的业务。因此为了解决有状态业务的需求,Docker 提出了卷(Volume)的概念
性能问题
UnionFS 对于修改删除等效率非常低。对于 I/O 要求比较高的应用,如 redis,在实现持久化存储时,底层存储的性能要求比较高,UnionFS并不合适
宿主机和容器互访不方便
宿主机访问容器,或者容器访问宿主机,要通过 docker cp 来完成,应用很难操作
容器之间共享不方便
1.3 存储卷分类
目前 Docker 提供了三种方式将数据从宿主机挂载到容器中
volume docker 管理卷:默认映射到宿主机的 /var/lib/docker/volumes 目录下,只需要在容器内指定容器的挂载点是什么,而被绑定宿主机下的那个目录,是由容器引擎 daemon 自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合
bind mount 绑定数据卷:映射到宿主机指定路径下,在宿主机上的路径要人工的指定一个特定的路径,在容器中也需要指定一个特定的路径,两个已知的路径建立关联关系
tmpfs mount 临时数据卷:映射到于宿主机内存中,一旦容器停止运行,tmpfs mounts 会被移除,数据就会丢失,用于高性能的临时数据存储
二、管理卷 volume
2.1 Volume命令
2.1.1 docker volume create
创建存储卷
docker volume create [OPTIONS] [VOLUME]
- -d,--driver:指定驱动,默认是 local
- --label:指定元数据
2.1.2 docker volume inspect
查看卷详细信息
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
- -f:指定相应个格式,如 json
2.1.3 docker volume ls
列出卷
docker volume ls [OPTIONS]
- --format:指定相应个格式,如 json,table
- --filter,-f:过滤
- -q:仅显示名称
2.1.4 docker volume rm
删除卷,使用中的无法被删除
docker volume rm [OPTIONS] VOLUME [VOLUME...]
- -f,--force:强制删除
2.1.5 docker volume prune
批量清理不再被任何容器使用的未命名数据卷
docker volume prune [OPTIONS]
- --filter:过滤
- -f,--force:不提示是否删除
2.2 创建卷
docker volume create
见上
-v 参数指定
功能:完成目录映射
docker run -v name:directory[:options]
- 第一个参数:卷名称
- 第二个参数:卷映射到容器的目录
- 第三个参数:选项,如 ro 表示 readonly
docker run -d \--name devtest \-v myvol2:/app \nginx:latest
通过 docker inspect 可以看到
"Mounts": [{"Type": "volume","Name": "myvol2","Source": "/var/lib/docker/volumes/myvol2/_data","Destination": "/app","Driver": "local","Mode": "","RW": true,"Propagation": ""}
],
--mount 参数指定
功能:完成目录映射
--mount '<key>=<value>,<key>=<value>'
- type:类型表示 bind,volume,or tmpfs
- source,src:对于命名卷,这是卷的名称。对于匿名卷,省略此字段
- destination,dst,target:文件或目录挂载在容器中的路径
- ro,readonly:只读方式挂载
docker run -d \--name devtest \--mount source=myvol2,target=/app \nginx:latest
通过 docker inspect 可以看到
"Mounts": [{"Type": "volume","Name": "myvol2","Source": "/var/lib/docker/volumes/myvol2/_data","Destination": "/app","Driver": "local","Mode": "","RW": true,"Propagation": ""}
],
Dockerfile匿名卷
通过 Dockerfile 的 VOLUME 可以创建 docker 管理卷。这个后续在 Dockerfile 中详细讲解
也可以通过 dockerfile 的 VOLUME 指令在镜像中创建 Data Volume,这样只要通过该镜像创建的容器都会存在挂载点,但是通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,而是由 docker 随机生成的
三、绑定卷 bind mount
3.1 -v 参数创建卷
完成卷映射
docker run -v name:directory[:options] .........
- 第一个参数:宿主机目录,这个和管理卷是不一样的
- 第二个参数:卷映射到容器的目录
- 第三个参数:选项,如 ro 表示 readonly
docker run -d \-it \--name devtest \-v "$(pwd)"/target:/app \nginx:latest
3.2 --mount 参数创建卷
完成目录映射
--mount '<key>=<value>,<key>=<value>'
- type:类型表示 bind, volume, or tmpfs
- source,src:宿主机目录,这个和管理卷是不一样的。
- destination,dst,target:文件或目录挂载在容器中的路径
- ro,readonly:只读方式挂载
docker run -d \-it \--name devtest \--mount type=bind,source="$(pwd)"/target,target=/app \nginx:latest
四、临时卷 tmpfs
临时卷数据位于内存中,容器和宿主机之外
tmpfs 局限性
- 不同于卷和绑定挂载,不能在容器之间共享 tmpfs 挂载
- 这个功能只有在 Linux 上运行 Docker 时才可用
指定 --tmpfs 创建
功能:完成临时卷映射
--tmpfs /app# 案例
docker run -d \
-it \
--name tmptest \
--tmpfs /app \nginx:1.22.1
--mount 指定参数创建
功能:完成目录映射
--mount '<key>=<value>,<key>=<value>'
- type:类型表示 bind,volume,or tmpfs
- destination,dst,target:挂载在容器中的路径
- tmpfs-size:tmpfs 挂载的大小(以字节为单位)。默认无限制
- tmpfs-mode:tmpfs 的八进制文件模式。例如,700 或 0770。默认为 1777 或全局可写
docker run -d \-it \--name tmptest \--mount type=tmpfs,destination=/app \nginx:latest