11.Docker存储管理

Docker Data Volume

Docker镜像由多个只读层叠加,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层

如果运行中的容器修改了现有一个已存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏;即“写时复制(COW)”机制

关闭并重启容器,其数据不受影响;但删除Docker容器,则其更改将会全部丢失

存在的问题

  • 存储于联合文件系统中,不易于宿主机访问;
  • 容器间数据不方便共享
  • 删除容器其数据会丢失

解决方案:”volume“

卷是容器上的一个或多个目录,此类目录可绕过联合文件系统(AUFS),与宿主机上的某目录绑定

volume的初衷是独立于容器生命周期实现数据持久化,因此删除容器不会删除卷

image

Docker的数据持久化即使数据不随着container的结束而结束,数据存在于host机器上——要么存在于host的某个指定目录中(使用bind mount),要么使用docker自己管理的volume(/var/lib/docker/volumes下)。

bind mount

bind mount自docker早期便开始为人们使用了,用于将host机器的目录mount到container中。需明确指定宿主机路径与容器内部路径,进行绑定;具有高耦合性,强自由行;

bind mount在不同的宿主机系统时不可移植的,比如Windows和Linux的目录结构是不一样的,bind mount所指向的host目录也不能一样。这也是为什么bind mount不能出现在Dockerfile中的原因,因为这样Dockerfile就不可移植了。

docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox
#查看bbox2容器的卷、卷标识符及挂载的主机目录(-f 指定Go模板)
docker inspect -f {{.mounts}} bbox2
#绑定当前路径下host-dava到容器/container-data下
docker run -it -v $(pwd)/host-dava:/container-data alpine sh

有几点需要注意:

  • host机器的目录路径必须为全路径(准确的说需要以/~/开始的路径),不然docker会将其当做volume而不是volume处理
  • 如果host机器上的目录不存在,docker会自动创建该目录
  • 如果container中的目录不存在,docker会自动创建该目录
  • 如果container中的目录已经有内容,那么docker会使用host上的目录将其覆盖掉

volume

只需指定容器内需要挂载路径,由docker daemon自动创建维护特定目录下;低耦合性,但无法指定特定宿主机路径

volume也是绕过container的文件系统,直接将数据写到host机器上,只是volume是被docker管理的,docker下所有的volume都在host机器上的指定目录下/var/lib/docker/volumes。

docker run -it -name bbox1 -v /data busybox
#查看bbox1容器的卷、卷标识符及挂载的主机目录
docker inspect -f {{.mounts}} bbox1

docker run -it -v my-volume:/mydata alpine sh

然后可以查看到给my-volume的volume:

docker volume inspect my-volume
[
    {
        "CreatedAt": "2019-08-28T19:42:49Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
        "Name": "my-volume",
        "Options": {},
        "Scope": "local"
    }
]
LowerDir: image镜像层(镜像本身,只读)
UpperDir:容器的上层(读写)
MergedDir:容器的文件系统,使用UnionFS(联合文件系统)将lowerdir和upperdir合并给容器使用
WorkDir:容器在宿主机的工作目录

可以看到,volume在host机器的目录为/var/lib/docker/volumes/my-volume/_data。此时,如果my-volume不存在,那么docker会自动创建my-volume,然后再挂载。

也可以不指定host上的volume:

docker run -it -v /mydata alpine sh

此时docker将自动创建一个匿名的volume,并将其挂载到container中的/mydata目录。匿名volume在host机器上的目录路径类似于:/var/lib/docker/volumes/30b32264cd0acfe8625e07edf156eb197716c20f69e7e9a053c87c2182b2e7d8/_data

创建volume

除了让docker帮我们自动创建volume,我们也可以自行创建:

docker volume create my-volume-2

然后将这个已有的my-volume-2挂载到container中:

docker run -it -v my-volume-2:/mydata alpine sh

需要注意的是,与bind mount不同的是,如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中,但是如果volume中已经有内容,则会将container中的目录覆盖。

创建数据容器(一个不运行的容器)

docker  run -it  -v /father/path:/child/path  --name data  ubuntu
exit
上面两步是创建号了数据container,接下来就用 --volumes--from 来挂载数据到新的容器中
docker  run -it   --volumes--from data    ubuntu

复制容器volume(共享容器存储)

单个容器的卷使用同一个主机目录

docker run -it --name c1 -v /docker/volume/v1:/data busybox
docker run -it --name c2 -v /docker/volume/v1:/data busybox

复制使用其它容器的卷,为docker run命令使用--volumes-from选项

docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox
docker run -it --name bbox2 --volumes-from bbox1 busybox

tmpfs

tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用

tmpfs,同时避免写入容器可写层提高性能。

# 使用--tmpfs
docker run -dit --name tmpfs-test --tmpfs /app busybox
原文地址:https://www.cnblogs.com/Gmiaomiao/p/14289243.html