Docker 数据卷
一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 54w+ 字,讲解图 2476+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 1900+ 小伙伴加入学习 ,欢迎点击围观
一、什么是数据卷?
简单来说,数据卷是一个可供一个或多个容器使用的特殊目录,用于持久化数据以及共享容器间的数据,它以正常的文件或目录的形式存在于宿主机上。 另外,其生命周期独立于容器的生命周期,即当你删除容器时,数据卷并不会被删除。
二、为什么需要数据卷?
Docker 镜像由多个文件系统(只读层)叠加而成。Docker 会加载只读镜像层,并在镜像栈顶部添加一个读写层。当运行容器后,如果修改了某个已存在的文件,那么该文件将会从下面的只读层复制到上面的读写层,同时,该文件在只读层中仍然存在。当我们删除 Docker 容器,并通过镜像重新启动容器时,之前的更改的文件将会丢失。
那么,要如何解决数据持久化的问题呢?于是,Docker 提出了 Volume 数据卷的概念。
三、数据卷特性
- 数据卷可以在容器之间共享和重用;
- 对数据卷的修改会立刻生效;
- 更新数据卷不会影响镜像;
- 数据卷默认一直存在,即使容器被删除;
四、挂载数据卷
Docker 提供了 3 种不同的方式将数据从宿主机挂载到容器中。
4.1 volume (最常用的方式)
volume : Docker 管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes
目录下, 也是最常用的方式。
看上图,所有的 Docker 容器数据都保存在 /var/lib/docker/volumes
目录下。若容器运行时未指定数据卷, Docker 创建容器时会使用默认的匿名卷(名称为一堆很长的 ID)。
注意:Mac 系统中, Docker 是基于虚拟机的 ,必须登录到虚拟机里面,登录后在目录
/var/lib/docker/volumes/
下即可找到数据卷。
4.2 bind mount(比较常用的方式)
bind mount: 意为可以存储在宿主机中的任意位置。需要注意的是,bind mount 在不同的宿主机系统时不可移植的,比如 Windows 和 Linux 的目录结构是不一样的,bind mount 所指向的 host 目录也不一样。这也是为什么 bind mount 不能出现在 Dockerfile 中的原因所在,因为这样 Dockerfile 就不可移植了。
4.3 tmpfs mount (一般不用这种方式)
tmpfs mount : 挂载存储在宿主机的内存中,而不会写入宿主机的文件系统,一般不用此种方式。
五、Volume 使用
5.1 创建一个数据卷
执行如下命令创建数据卷:
docker volume create test-vol
5.2 查看所有的数据卷
docker volume ls
5.3 查看数据卷信息
执行如下命令,可以查看指定的数据卷信息:
# 查看数据卷名为 test-vol 的信息
docker volume inspect test-vol
5.4 运行容器时挂载数据卷
数据卷 test-vol
创建成功后,我们运行一个 Nginx 容器,并尝试挂载该数据卷,挂载命令支持两种:
-v
docker run -d -it --name=test-nginx -p 8011:80 -v test-vol:/usr/share/nginx/html nginx:1.13.12
参数说明:
-d
: 后台运行容器;--name=test-nginx
: 指定容器名为 test-nginx;-p 8011:80
: 将容器的 80 端口挂载到宿主机的 8011 端口;-v test-vol:/usr/share/nginx/html
: 将test-vol
数据卷挂载到容器中的 /usr/share/nginx/html 目录上;
--mount
docker run -d -it --name=test-nginx -p 8011:80 --mount source=test-vol,target=/usr/share/nginx/html nginx:1.13.12
参数说明:
--mount source=test-vol,target=/usr/share/nginx/html
: 将test-vol
数据卷挂载到容器中的 /usr/share/nginx/html 目录上;
-v
和 --mount
有什么区别?
都是挂载命令,使用 -v
挂载时,如果宿主机上没有指定文件不会报错,会自动创建指定文件;当使用 --mount
时,如果宿主机中没有这个文件会报错找不到指定文件,不会自动创建指定文件。
容器运行成功后,进入到 /var/lib/docker/volumes
目录下,验证数据是否挂载成功:
可以看到已经有了 50x.html
、 index.html
两个 Nginx 页面相关数据,说明数据卷挂载成功了。挂载成功后,我们不论是修改 /var/lib/docker/volumes
下的数据,还是进入到容器中修改 /usr/share/nginx/html
下的数据,都会同步修改对应的挂载目录,类似前端开发中双向绑定的作用。
下面,我们停止并删除刚刚运行的 Nginx 容器, 看看数据卷中的数据是否会跟着被删除:
可以发现数据卷相关数据都还在,表明数据卷的生命周期独立于容器。另外,若下次再创建 Nginx 容器,还可以复用这个数据卷,复用性以及扩张性都非常不错。
删除数据卷
由于数据卷的生命期独立于容器,想要删除数据卷,就需要我们手动来操作, 执行命令如下:
docker volume rm test-vol
如果你需要在删除容器的同时移除数据卷,请使用
docker rm -v
命令。对于那些没有被使用的数据卷,可能会占用较多的磁盘空间,你可以通过如下命令统一删除:
docker volume prune
bind mount 使用
通过 bind mount 模式可以挂载到宿主机的任意位置,示例如下:
docker run -d -it --name=test-nginx -p 8011:80 -v /docker/nginx1:/usr/share/nginx/html nginx:1.13.12
参数说明:
-v /docker/nginx1:/usr/share/nginx/html
: 将宿主机中的/docker/nginx1
目录挂载到容器中的/usr/share/nginx/html
目录;
容器运行成功后,进入容器中:
docker exec -it test-nginx /bin/bash
从上图可以看到,与 volume 不同,bind mount 这种方式会隐藏目录中的内容(非空情况下),这里的 /usr/share/nginx/html
目录下的 html 文件被隐藏了,所以我们看不到。
但是,我们可以将宿主机中该目录中的文件立刻挂载到容器中,下面验证一下:
- 新建一个
index.html
:
- 再次进入容器,查看挂载目录内容: