存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。
在宿主机上的这个与容器形成绑定关系的目录被称作存储卷。卷的本质是文件或者目录,它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。
比如说宿主机的/data/web 目录与容器中的/tmp/web 目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器写入内容, 容器和宿主机的数据读写是同步的。
数据丢失问题
容器安装业务类型,可以分为两大类:
无状态的(数据不需要被持久化)
有状态的(数据需要被持久化)
显然容器更擅长无状态的应用,因为无状态的数据不能持久化存储,那么容器的根目录的生命周期就和容器的生命周期是一致的。容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对任何文件的修改都存在于该读写层,只要容器被销毁那么数据也就随之被销毁了。
虽然容器希望所有的业务都尽量保持无状态,这样容器就可以开箱即用,并且可以任意调度,但实际业务总是有各种需要数据持久化的场景,比如 MySQL 等有状态的业务。因此为了解决有状态业务的需求, Docker 提出了卷(Volume)的概念 。
性能问题
UnionFS 对于修改删除等,一般效率非常低,如果对一于 I/O 要求比较高的应用,如redis 在实现持化存储时,是在底层存储时的性能要求比较高。
宿主机和容器互访不方便
宿主机访问容器,或者容器访问要通过 docker cp 来完成,应用很难操作
容器和容器共享不方便
目前 Docker 提供了三种方式将数据从宿主机挂载到容器中
存储卷可以通过命令方式创建,也可以在创建容器的时候通过 -v and --mount
指定
命令 | 别名 | 功能 |
---|---|---|
docker volume create | 创建存储卷 | |
docker volume inspect | 显示存储卷详细信息 | |
docker volume ls | docker volume list | 列出存储卷 |
docker volume prune | 清理所有无用数据卷 | |
docker volume rm | 删除卷,使用中的无法删除 |
docker volume create
功能:创建存储卷
docker volume create [OPTIONS] [VOLUME]
关键参数
○ -d, --driver: 指定驱动,默认是 local
○ --label: 指定元数据
docker volume inspect
功能:查看卷详细信息
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
关键参数
○ -f: 指定相应个格式,如 json
docker volume ls
功能:列出卷
docker volume ls [OPTIONS]
关键参数
docker volume rm
功能:删除卷,需要容器不使用
docker volume rm [OPTIONS] VOLUME [VOLUME...]
关键参数
○ -f,–force:强制删除
docker volume prune
功能:删除不使用的本地卷
docker volume prune [OPTIONS]
关键参数
○ --filter:过滤
○ -f, --force :不提示是否删除
-v 和-mount 都可以完成管理卷的创建
-v 参数
• 功能:完成目录映射
docker run -v name:directory[:options] ......
参数
○ 第一个参数:卷名称
○ 第二个参数:卷映射到容器的目录
○ 第三个参数:选项,如 ro 表示 readonly
[root@aliyun ~]# docker run -d --name test -v myvol:/app nginx:latest
[root@aliyun ~]# docker inspect myvol
[
{
"CreatedAt": "2023-09-14T14:55:36+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/data/var/lib/docker/volumes/myvol/_data",
"Name": "myvol",
"Options": null,
"Scope": "local"
}
]
–mount 参数
功能:完成目录映射
--mount '=,='
关键参数
○ type : 类型表示 bind, volume, or tmpfs
○ source , src :对于命名卷,这是卷的名称。对于匿名卷,省略此字段。
○ destination, dst,target:文件或目录挂载在容器中的路径
○ ro,readonly: 只读方式挂载
[root@aliyun ~]# docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest
通过命令查看信息
[root@aliyun ~]# docker inspect devtest
Docker -v 创建管理卷
1.-v 创建管理卷,并且启动容器
[root@aliyun ~]# docker container run --name nginx -d -p 80:80 -v test_volmue2:/usr/share/nginx/html:ro nginx:latest
指定 ro 的话宿主机可以修改,但是容器里面无法修改
通过 Dockerfile 的 VOLUME 可以创建 docker 管理卷。我们也可以通过 dockerfile 的 VOLUME 指令在镜像中创建 Data Volume,这样只要通过该镜像创建的容器都会存在挂载点,但值得注意的是通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,而是由 docker 随机生成的 。
宿主机和容器之间数据是同步的,无论是mount 创建的卷数据也会完成同步
-v创建管理卷
[root@aliyun ~]# docker container run --name nginx -d -p 80:80 -v test_volume2:/usr/share/nginx/html nginx:latest
j进入卷目录
[root@aliyun ~]# cd /data/var/lib/docker/volumes/test_volume2/_data/
[root@aliyun _data]# ls
50x.html index.html
注意此时可以看到容器里面的内容自动的放到了宿主机里面,也就
是说宿主机上没有容器会拷贝过去
清理释放空间
进入卷目录查看可以看到文件并没有被删除
[root@aliyun _data]# docker stop nginx
nginx
[root@aliyun _data]# docker rm nginx
nginx
[root@aliyun _data]# ls
50x.html index.html
-v 创建管理卷,并且启动 2 容器,指定同一个卷
[root@aliyun _data]# docker container run --name nginx1 -d -p 80:80 -v test_volume:/usr/share/nginx/html nginx:latest
[root@aliyun _data]# docker container run --name nginx_my -d -p 6060:80 -v test_volume:/usr/share/nginx/html nginx:latest
进入卷目录修改html
[root@aliyun _data]# ls
50x.html index.html
访问80和6060端口发现首页都被修改了
-v 和-mount 都可以完成绑定卷的创建
功能:完成卷映射
docker run -v name:directory[:options] .........
参数
○ 第一个参数: 宿主机目录,这个和管理卷是不一样的
○ 第二个参数:卷映射到容器的目录
○ 第三个参数:选项,如 ro 表示 readonly
–mount 参数创建绑定卷
功能:完成目录映射
--mount '=,='
关键参数
○ type : 类型表示 bind, volume, or tmpfs
○ source , src : 宿主机目录,这个和管理卷是不一样的。
○ destination, dst,target:文件或目录挂载在容器中的路径
○ ro,readonly: 只读方式挂载
容器该目录本身存在的文件消失不见, 这是 bind mount 模式和 volume 模式最大的不同点
使用-mount 方式创建容器: 创建 nginx 容器,并将宿主机/webapp1 目录挂载至
容器/usr/share/nginx/html 目录,注意如果 webapp1 目录不存在会启动报错
[root@aliyun ~]# docker run -d -p 80:80 --name bind1 --mount type=bind,source=/data/webapp1,target=/usr/share/nginx/html/ nginx:latest
如果宿主机和容器的目录内容一致,会以宿主机目录为准
-v 创建绑定卷
使用-v 方式创建容器: 创建 nginx 容器,并将宿主机/webapp2 目录挂载至容器
/usr/share/nginx/html 目录,注意如果 webapp2 目录不存在,启动不会报错,这是-
v 和–mount 方式的区别,同样内容相同是以宿主机为准。
[root@aliyun ~]# docker run -d -p 8080:80 --name bind2 -v /data/webapp4:/usr/share/nginx/html nginx:latest
绑定卷共享和管理卷类似
临时卷数据位于内存中,在容器和宿主机之外。
tmpfs 局限性
• 不同于卷和绑定挂载,不能在容器之间共享 tmpfs 挂载。
• 这个功能只有在 Linux 上运行 Docker 时才可用
功能:完成临时卷映射
[root@aliyun ~]# docker run -d -it --name tmpfs_test --tmpfs /app nginx
功能:完成目录映射
--mount '=,='
关键参数
○ type : 类型表示 bind, volume, or tmpfs
○ destination, dst,target:挂载在容器中的路径
○ tmpfs-size: tmpfs 挂载的大小(以字节为单位)。默认无限制。
○ tmpfs-mode: tmpfs 的八进制文件模式。例如, 700 或 0770。默认为 1777
或全局可写
[root@aliyun ~]# docker container run --name tmpfs_test -d -p 80:80 --tmpfs /usr/share/nginx/html/ nginx:latest
[root@aliyun ~]# docker exec -it tmpfs_test bash
root@acba8a252814:/# ls /usr/share/nginx/html/
root@acba8a252814:/#
进入容器可以看到 nginx 里面的文件被覆盖了,也就是说 tmpfs 也会覆盖容器里
面的文件
注意重启后mpfs 内容完全消失了,也就是说内容是存在内存里面的。