docker 数据卷

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,由多个键值对组成,由,分隔,每个由一个<key=<value>>元组组成。
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

数据的覆盖问题

如果挂载一个空的数据卷到容器中的一个非空目录中,那么这个目录下的文件会被复制到数据卷中。

如果挂载一个非空的数据卷到容器中的一个目录中,那么容器中的目录中会显示数据卷中的数据。如果原来容器中的目录中有数据,那么这些原始数据会被隐藏掉。

使用数据卷的最佳场景

在多个容器之间共享数据,多个容器可以同时以只读或者读写的方式挂载同一个数据卷,从而共享数据卷中的数据。

当宿主机不能保证一定存在某个目录或一些固定路径的文件时,使用数据卷可以规避这种限制带来的问题。

当你想把容器中的数据存储在宿主机之外的地方时,比如远程主机上或云存储上。

当你需要把容器数据在不同的宿主机之间备份、恢复或迁移时,数据卷是很好的选择。

转载自杨奇龙博客

posted @ 2023-08-01 11:02  Cetus-Y  阅读(24)  评论(0编辑  收藏  举报