Pexels 上的 Aleksandar Pasaric 拍摄的图片
前言
Docker 镜像是由多个文件系统(只读层)叠加而成。当我们启动一个容器的时候,Docker 会加载只读镜像层并在其上(镜像栈顶部)添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。
如何解决数据持久化问题?
为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,数据卷是存在于一个或多个容器中的特定文件或文件夹,它可以绕过默认的联合文件系统,以正常的文件或者目录的形式存在于宿主机上。其生存周期独立于容器的生存周期。
目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中:
volumes:Docker管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录中最常用的方式。
由上图可以知道,目前所有Container的数据都保存在了这个目录下边,由于没有在创建时指定卷,所以Docker帮我们默认创建许多匿名(就上面这一堆很长ID的名字)卷。
bind mounts:意为着可以存储在宿主机系统的任意位置;
bind mount在不同的宿主机系统时不可移植的,比如Windows和Linux的目录结构是不一样的,bind mount所指向的host目录也不能一样。这也是为什么bind mount不能出现在Dockerfile中的原因,因为这样Dockerfile就不可移植了。
tmpfs:挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统。
实践
docker 专门提供了 volume 子命令来操作数据卷:
create 创建数据卷
inspect 显示数据卷的详细信息
ls 列出所有的数据卷
prune 删除所有未使用的 volumes,并且有 -f 选项
rm 删除一个或多个未使用的 volumes,并且有 -f 选项
创建数据卷 myvol
➜ ~ docker volume create myvol
myvol
➜ ~ docker volume ls
DRIVER VOLUME NAME
local myvol
➜ ~ docker volume inspect myvol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/myvol/_data",
"Name": "myvol",
"Options": {},
"Scope": "local"
}
]
需要注意的是 对于linux ,docker的数据卷可以在 /var/lib/docker/volumes/
中找到,但是对于mac系统 docker 是基于虚拟机的 ,必须登录到虚拟机里面
screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
然后在目录 /var/lib/docker/volumes/
里面找到数据卷。
使用容器卷
docker (17.0.6版本之后)提供两种命令行方式使用数据卷,-v /--mount,具体用法如下:
-v/--volume,由(:)分隔的三个字段组成,卷名:容器路径:选项列表。选项列表可以ro/rw。
--mount,由多个键值对组成,由,分隔,每个由一个>元组组成。type,值可以为 bind,volume,tmpfs。source,对于命名卷,是卷名。对于匿名卷,这个字段被省略。可能被指定为 source 或 src。
destination,文件或目录将被挂载到容器中的路径。可以指定为 destination,dst 或 target。
volume-opt 可以多次指定。
用卷启动容器
启动一个名为 devtest 的容器,并将 myvol 挂载到 容器中的/app 目录。
➜ ~ docker run -d -it --name devtest -v myvol:/app nginx:latest
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
852e50cd189d: Pull complete
a29b129f4109: Pull complete
b3ddf1fa5595: Pull complete
c5df295936d3: Pull complete
232bf38931fc: Pull complete
Digest: sha256:c3a1592d2b6d275bef4087573355827b200b00ffc2d9849890a4f3aa2128c4ae
Status: Downloaded newer image for nginx:latest
1dda50366461fd2add9e8dbd367d23676762a575d306db65361a2bfcad3a8264
在容器中的数据卷里面创建文件并写入
➜ ~ docker exec -it 1dda50366461 /bin/bash
root@1dda50366461:/#
root@1dda50366461:/# cd app/
root@1dda50366461:/app# ls
root@1dda50366461:/app# echo volume > 20201123
在mac的虚拟机上查看对应的文件目录,
Docker 挂载数据卷的默认权限是可读写(rw),用户也可以通过 ro 标记指定为只读:
docker run -d -it --name devtest -v myvol:/app:ro nginx:latest
停止容器和清理卷
docker container stop devtest
docker container rm devtest
docker volume rm myvol
数据的覆盖问题
如果挂载一个空的数据卷到容器中的一个非空目录中,那么这个目录下的文件会被复制到数据卷中。
如果挂载一个非空的数据卷到容器中的一个目录中,那么容器中的目录中会显示数据卷中的数据。如果原来容器中的目录中有数据,那么这些原始数据会被隐藏掉。
使用数据卷的最佳场景
在多个容器之间共享数据,多个容器可以同时以只读或者读写的方式挂载同一个数据卷,从而共享数据卷中的数据。
当宿主机不能保证一定存在某个目录或一些固定路径的文件时,使用数据卷可以规避这种限制带来的问题。
当你想把容器中的数据存储在宿主机之外的地方时,比如远程主机上或云存储上。
当你需要把容器数据在不同的宿主机之间备份、恢复或迁移时,数据卷是很好的选择。
![d7c79faf5935c028d78adae272ce007b.gif](https://i-blog.csdnimg.cn/blog_migrate/578a38624a31f8e4c90fcae7d18e5447.gif)
一文了解Docker
数据库部署是否合适容器化?
使用Docker安装MySQL
-The End-
本公众号长期关注于数据库技术以及性能优化,故障案例分析,数据库运维技术知识分享,个人成长和自我管理等主题,欢迎扫码关注。