Docker Volume

"Ice in my vein"


Docker Volume(存储卷)

什么是存储卷?

存储卷就是: "将宿主机的本地文件系统中存在的某个目录,与容器内部的文件系统上的某一目录建立绑定关系"。

存储卷与容器本身的联合文件系统?

在宿主机上的这个与容器形成绑定关系的目录被称作"存储卷"。而这个卷的本质就是文件或者目录,它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。

使得**可以在宿主机和容器内共享数据库内容****。**让容器直接访问宿主机中的内容,也可以宿主机向容器写入内容,容器和宿主机的数据读写是同步的

为什么需要存储卷?

存储卷技术的产生,主要来源于解决四个问题的需求。

✨ 数据丢失
容器按照业务类型,总体可以分为两类:

• 无状态(数据不需要被持久化)

• 有状态(数据需要被持久化)

显然,容器更擅长无状态应用。因为,容器根目录的生命周期,同容器的生命周期一样。容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。

但实际业务总是有各种需要数据持久化的场景: 比如 MySQL、Kafka 等有状态的业务。所以,Docker 提出了卷(volume)的概念

✨ 性能问题

UnionFS 对于修改删除等,一般效率非常低。
✨ 宿主机和容器互访不方便
宿主机访问容器,或者容器访问要通过 docker cp 来完成,应用很难操作。
✨ 容器和容器共享不方便
两个容器内部不同的目录,同时绑定宿主机上的某一目录,就可以实现数据共享。

存储卷分类

目前 Docker 提供了三种方式将数据从宿主机挂载到容器中:

🩰 volume docker 管理卷

🩰 bind mount 绑定数据卷

🩰 tmpfs mount 临时数据卷

下图表示三类存储卷,在Docker存储卷中的结构:


存储卷详解

管理卷 Volume

docker管理卷默认映射到宿主机的 /var/lib/docker/volumes(如果修改了默认目录,就不是这条路径)目录下,只需要在容器内指定要挂在点是什么。容器引擎daemon会自行创建一个空的目录在被绑定的宿主机目录下。或者使用一个已经存在的目录,与存储卷建立存储关系。

这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合。

创建卷:

存储卷可以通过命令方式创建,也可以通过在创建容器的时候通过 -v and --mount 指定。

方法一:Volume 命令操作

操作docker管理卷的命令清单如下:

|-----------------------|--------------------|------------|
| 命令 | 别名 | 功能 |
| docker volume create | | 创建存储卷 |
| docker volume inspect | | 显示存储卷的详细信息 |
| docker volume ls | docker volume list | 列出存储卷 |
| docker volume prune | | 清理无用的存储卷 |
| docker volume rm | | 删除存储卷 |

🎱 docker volume create

语法:

bash 复制代码
# 创建存储卷
docker volume create [OPTIONS] [VOLUME]

OPTIONS:
-d, --driver:指定驱动,默认是 local
--label:指定元数据

🎱 docker volume inspect

语法:

bash 复制代码
# 查看卷详细信息
docker volume inspect [OPTIONS] VOLUME [VOLUME...]

OPTIONS:
-f:指定相应个格式

🎱 docker volume ls

语法:

bash 复制代码
# 列出卷
docker volume ls [OPTIONS]

OPTIONS:
--format:指定相应个格式
--filter,-f: 过滤
-q: 仅显示名称    

🎱 docker volume rm

语法:

bash 复制代码
# 删除卷,需要容器不使用    
ocker volume rm [OPTIONS] VOLUME [VOLUME...]

OPTIONS:
-f,--force:强制删除

🎱 docker volume prune

语法:

bash 复制代码
# 删除不使用的本地卷
docker volume prune [OPTIONS]

OPTIONS:
--filter:过滤
-f, --force :不提示是否删除
方法二: -v 或者 --mount 指定
bash 复制代码
# -v参数 完成目录映射
docker run -v name:directory[:options]

ARGS:
name:卷名称
directory:卷映射到容器的目录
options:如 ro 表示 readonly
bash 复制代码
# --mount 参数

--mount '<key>=<value>,<key>=<value>'

ARGS:
type:类型表示 bind, volume, or tmpfs
source\src :对于命名卷,这是卷的名称。[对于匿名卷,省略此字段]
destination\dst\target:文件或目录挂载在容器中的路径
ro,readonly: 只读方式挂载
方法三: Dockerfile 匿名卷

通过Dockerfile的VOLUME可以创建docker管理卷。但不在本篇细说。

操作案例:

Docker 命令创建管理卷

使用 "docker create" 创建一个名为 "test_volume"的存储卷:

输入 "docker volume ls" 查看我们创建的存储卷:

检查存储卷的内部信息"docker volume inspect":

我们现在访问这个目录:

此时可以发现,该目录是被自动创建的空目录。

我们给该存储卷分配给一个nginx容器时,就会发现:

宿主机和容器之间数据是同步的

Docker -v 创建管理卷

-v 创建管理卷,并且启动容器:

bash 复制代码
docker run --name nginx1 -d -p 80:80 
    -vtest_volume:/usr/share/nginx/html:ro nginx:1.24.0

进入卷的目录:

我们看到,创建docker管理卷后,宿主机的目录同容器目录文件实际是共享的~我们可以借此修改index.html文件:

这是修改前的原Nginx首页:

修改后(注:我们是在宿主机的目录,对这个首页文件进行修改):

我们再次进入docker容器中,看看修改容器内的文件后,宿主机会不会更新:

我们会发现,在容器内部是不能对该关联目录内的文件进行修改的!答案是,我们在创建管理卷的时候,设置了"ro"参数 ------ 所以,这个ro参数针对的对象是,谨防从容器内部对文件进行修改!

最后,我们再清理释放空间。

指定 ro 的话宿主机可以修改,但是容器里面无法修改

Docker mount 创建管理卷

mount 创建管理卷,并且启动容器:

bash 复制代码
docker run -d -p 80:80 --name nginx 
--mount    
    type=volume,source=test_volume,target=/usr/share/nginx/html nginx:latest

ARGS:
type有很多: volume表示管理存储卷 bind表示绑定存储卷 tmpfs表示临时存储卷

查看卷、容器创建成功:

查看卷挂载点:

Docker 卷生命周期

我们继续上接前文,为一个nginx容器创建了一个存储卷,我们可以在容器内、宿主机上找到这个存储卷同步的内容:

当我们将容器删除时:

存储卷的内容还是存在的,如果此时我们使用命令删除存储卷时,存储卷的内容就会被彻底清空:

Docker 卷共享

-v 创建管理卷,并且启动 2 容器,指定同一个存储卷。

bash 复制代码
docker container run --name nginx1 -d -p 80:80 
    -v mutual_volume:/usr/share/nginx/html nginx:1.24.0
docker container run --name nginx2 -d -p 81:80 
    -v mutual_volume:/usr/share/nginx/html nginx:1.23.0

观察存储卷信息,修改 index.html:

观察容器内部的文件,发现都是同一份:

绑定卷 bind mount

绑定数据卷,需要人工在宿主机上指定一个特定路径,在容器中指定一个特定路径,再建立这两个特定路径的关联。

与管理卷不同,绑定卷的有些参数是不一样的。

bash 复制代码
docker run -v name:directory[:options]

ARGS:
name:宿主机目录,这个和管理卷是不一样的
bash 复制代码
--mount '<key>=<value>,<key>=<value>'

ARGS:
source\src: 宿主机目录,这个和管理卷是不一样的

其余参数都大差不差,咱们在这儿就不多费舌,直接上操作案例。

操作案例:

--mount 创建管理卷

使用-mount 方式创建容器:

创建 nginx 容器,并将宿主机 "/webapp" 目录挂载至容器"/usr/share/nginx/html"目录。

注:如果这个目录不存在,就会报错

bash 复制代码
docker run -d -p 80:80 --name bind 
--mount
    type=bind,source=/data/webapp,target=/usr/share/nginx/html nginx:1.23.0

# source:人为指定路径

查看挂载信息:

bash 复制代码
 docker inspect bind

进入容器的终端,查看挂载点目录,和在宿主机上查看里面都是没有文件:


这是 bind mount 模式和 volume 模式最大的不同点!!
我们在宿主机上添加 index.html,通过浏览器,我们可以访问到这个文件内容:


删除容器,然后查看宿主机上的文件 , 还是存在,说明容器删除并不影响 bind 映射。

-v 创建绑定卷

使用-v 方式创建容器: 创建 nginx 容器:

并将宿主机/webapp2 目录挂载至容器 /usr/share/nginx/html 目录。注:当目录不存在时,仍然会报错。

bash 复制代码
docker run -d -p 80:80 --name bind 
    -v /data/webapp2:/usr/share/nginx/html nginx:1.23.0

查看挂在信息:

后面的演示情况可以参照 使用 --mount方式创建的存储卷。

绑定卷共享

我们启动两个绑定卷,都绑定到宿主机的同一个目录:

我们使用本机回环,这两个容器看到的内容是一样的。

临时卷 tmpfs

临时卷数据位于内存中,在容器和宿主机之外。映射到于宿主机内存中,一旦容器停止运行,tmpfs mounts就会被移除,数据就会丢失,用于高性能的临时数据存储。

tmpfs 局限性:

🪀 不同于卷和绑定挂载,不能在容器之间共享 tmpfs 挂载

🪀 这个功能只有在 Linux 上运行 Docker 时才可用

创建卷:

方式一: 指定--tmpfs 创建
bash 复制代码
--tmpfs /path
方式二:--mount 指定参数创建
bash 复制代码
--mount '<key>=<value>,<key>=<value>'

OPTIONS:
destination,dst,target:挂载在容器中的路径
tmpfs-size:tmpfs 挂载的大小(以字节为单位)。默认无限制
tmpfs-mode:tmpfs 的八进制文件模式。例如,700 或 0770。默认为 1777或全局可写

操作案例:

tmpfs 参数创建临时卷

创建临时卷并启动容器

bash 复制代码
docker container run --name tmpfs -d -p 80:80 
    --tmpfs /usr/share/nginx/html/ nginx:latest

进入容器可以看到 nginx 里面的文件被覆盖了,也就是说 **tmpfs也会覆盖容器里面的文件。**绑定卷也是如此。

添加一个首页:

我们可以在浏览器中查看:

我们现在重启容器,发现之前的文件不存在了!

mount 创建临时卷

创建临时卷并启动容器:

bash 复制代码
docker container run --name tmpfs -d -p 80:80 
--mount
    type=tmpfs,target=/usr/share/nginx/html,tmpfs-size=1m nginx:1.23.0

添加一个首页:

tmp-size:

拷贝一个大文件到容器里面:

拷贝文件到我们的卷目录,超过了限制(tmpfs-size),空间限制为了 1m,会提示没有空间。

tmpfs 失踪了

创建一个普通的容器:

bash 复制代码
docker run -d -it --name tmpfs nginx:1.23.0 

在容器里面写入一个文件 mylabel.txt:

我们在宿主机上查找文件,文件被找到了,是因为他在容器的可写层:

我们再创建个临时卷:

bash 复制代码
docker run -d --name tmpfs2 --tmpfs /app nginx:1.24.0

进入容器,在/app 目录下创建 mynewlabel.txt。

在宿主机上查找 mynewlabel.txt,可以发现,文件找不到。

所以 tmpfs 的内容不是存储在我们的容器的可写层里面的。更加进一步佐证其存储的位置是在内存上。


本篇到此结束,感谢你的阅读。

相关推荐
Bright16684 小时前
centos9安装k8s集群
云原生·容器·kubernetes
!!!5256 小时前
华为云镜像加速器
docker·容器·华为云
xidianjiapei0017 小时前
Kubernetes的Ingress 资源是什么?
云原生·容器·kubernetes
sszdzq8 小时前
Docker
运维·docker·容器
dmy9 小时前
docker 快速构建开发环境
后端·docker·容器
土豆沒加10 小时前
K8S的Dashboard登录及验证
云原生·容器·kubernetes
终端行者11 小时前
kubernetes1.28部署mysql5.7主从同步,使用Nfs制作持久卷存储,适用于centos7/9操作系统,
数据库·容器·kubernetes
2401_8979300611 小时前
linux系统如何配置host.docker.internal
linux·docker·eureka
亲持红叶16 小时前
open-webui安装
docker·open-webui
伪装成塔的小兵16 小时前
Windows使用docker部署fastgpt出现的一些问题
windows·docker·容器·oneapi·fastgpt