码迷,mamicode.com
首页 > 其他好文 > 详细

Docker 存储卷

时间:2020-06-04 01:38:09      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:运行   pat   版本   tap   user   c11   永久   堆叠   信息   

Docker的两类存储资源

storage driver

Docker镜像的分层结构

技术图片

容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中。
分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于Docker storage driver。正是storage driver实现了多层数据的堆叠并为用户提供个单一 的合并之后的统一 视图。
Docker支持多种storage driver,有AUFS ,Device Mapper, Btrfs, OverlayFS, VFS 和ZFS。它们都能实现分层的架构,同时又有各自的特性。Docker 官方给优先使用Linux发行版默认的storage driver。
Docker安装时会根据当前系统的配置选择默认的driver.默认driver具有最好的稳定性,因为默认driver在发行版上经过了严格的测试。

运行docker info查看centos的默认driver:

docker info

Ubuntu用的AFUS,底层文件系统是extfs,各层数据存放在 /var/lib/docker/aufs。

Redhat/CentOS的默认driver是Device Mapper, SUSE 则是Btrfs。
对于某些容器,直接将数据放在由storage driver。

Data Volume之bind mount

storage driver和data volume是容器存放数据的两种方式。

Data Volume本质上是Docker Host文件系统中的目录或文件,能够直接被mount到容器的文件系统中。Data Volume有以下特点:

  1. Data Volume是目录或文件,而非没有格式化的磁盘(块设备) .
  2. 容器可以读写volume中的数据。
  3. volume数据可以被永久的保存,即使使用它的容器已经销毁。

这是需要持久化的数据,并且应该与镜像分开存放。

在具体的使用上,docker提供了两种类型的volume:bind mount 和 docker managed volume。

bind mount

bind mount是将host上已存在的目录或文件mount到容器。

[root@localhost ~]# mkdir /htdocs
[root@localhost ~]# mv index.html  /htdocs/

通过 -v将其mount到httpd容器:

[root@localhost ~]# docker run -d -p 8000:80 -v /htdocs/:/usr/local/apache2/htdocs httpd

-v的格式为:/usr/local/apache2/htdocs 就是apache server存放静态文件的地方。由于/usr/oca/apache2/htdocs已经存在,原有数据会被隐藏起来,取而代之的是host /htdocs/中的数据,这与linux mount命令的行为是致的。

[root@localhost ~]# curl 127.0.0.1:8000
<html>
<body>
<h1>this is test</h1>
</body>
</html>

curl显示的确实是/htdocs/html.index的内容,更新一下:

[root@localhost ~]# echo "hug"  > /htdocs/index.html 
[root@localhost ~]# curl 127.0.0.1:8000
hug

确实生效了,bind mount 可以让 host 与容器共享数据。

把容器销毁,对bind mount 也不会有什么影响。

另外还可以指定数据的读写权限,默认是可读写,
指定为只读:

[root@localhost ~]# docker run -d -p 8000:80 -v /htdocs/:/usr/local/apache2/htdocs:ro httpd

在容器中是无法修改的,只有host有权限修改

除了bind mount 目录,还可以单独指定一个文件:

docker run -d -p 8000:80 -v /htdocs/test.index:/usr/local/apache2/htdocs/test.index httpd

使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录bind mount给容器。
mount point有很多应用场景,比如我们可以将源代码目录mount到容器中,在host中修改代码就能看到应用的实时效果。再比如将mysql容器的数据放在bind mount里,这样host可以方便地备份和迁移数据。
bind mount的使用直观高效,易于理解,但它也有不足的地方: bind mount需要指定host文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他host,而该host没有要mount的数据或者数据不在相同的路径时,操作会失败。

docker managed volume

在使用上不需指定mount 源,指名 mount point 就行了。

[root@localhost ~]# docker run -d -p 8000:80 -v /usr/local/apache2/htdocs httpd

我们通过-v告诉 docker 需要一个 data volume,并将其 mount 到 /usr/local/apache2/htdocs。
data volume 可以在容器的配置信息中找到:

[root@localhost ~]# docker inspect f480d2
Mounts": [
        {
            "Type": "volume",
            "Name": "3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46",
            "Source": "/var/lib/docker/volumes/3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46/_data",
            "Destination": "/usr/local/apache2/htdocs",

Source 就是该 volume 在host上的目录。
每当容器申请mount docker managed volume时,docker都会在/var/lib/docker/volumes 下生成一个目录,这个目录就mount源。

[root@localhost ~]# ls /var/lib/docker/volumes/3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46/_data/

还可以用 docker volume查看目录:

[root@localhost ~]# docker volume  inspect 3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46
[
    {
        "CreatedAt": "2020-06-02T17:50:00+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46/_data",
        "Name": "3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46",
        "Options": null,
        "Scope": "local"
    }
]

目前,docker volume只能查看docker managed volume,还看不到 bind mount,也无法知道volume对应的容器。

查看index:

[root@localhost ~]# curl 127.0.0.1:8000
<html><body><h1>It works!</h1></body></html>

可以直接修改index,或添加一个index:

[root@localhost ~]# vim /var/lib/docker/volumes/3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46/_data/index.html 
[root@localhost ~]# vim /var/lib/docker/volumes/3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46/_data/test.index
bind mount 与 docker managed volume的区别

相同:两者都是 host 文件系统的某个路径

不同:
技术图片

共享数据

共享数据是 volume 的关键特性, volume 如何在容器与host之间,容器与容器之间共享数据。

容器与host共享数据

有两种类型的data volume,它们均可实现在容器与host之间共享数据,但方式有所区别。
对于bind mount是非常明确的:直接将要共享的目录mount到容器。具体请参考前面httpd的例子,不再赘述。
docker managed volume就要麻烦点。由于volume位于host中的目录,是在容器启动时才生成,所以需要将共享数据拷拷贝到 volume中。

[root@localhost ~]# docker run -d -p 8000:80 -v /usr/local/apache2/htdocs httpd
[root@localhost ~]# curl 127.0.0.1:8000
<html><body><h1>It works!</h1></body></html>
[root@localhost ~]# docker cp /htdocs/index.html  97373dd7f9b15f241:/usr/local/apache2/htdocs
[root@localhost ~]# curl 127.0.0.1:8000
hug

Docker cp可以在容器与host之间拷贝数据,也可以直接通过Linux的cp命令复制到/var/lib/docker/volumes/。

容器之间共享数据

第一种可以将共享数据放在 bind mount 中,然后将其 mount 到多个容器。

将 /htdocs mount 到三个httpd容器:

[root@localhost ~]# docker run --name web1 -d -p 80 -v /htdocs:/usr/local/apache2/htdocs httpd
b004d4df2fe4667d01e15b1a936afd726ac7ef896dba9336d064636018cd0ab3
[root@localhost ~]# docker run --name web2 -d -p 80 -v /htdocs:/usr/local/apache2/htdocs httpd
fe50f6b90793bfd385ea86ad205cab2a20b3985f911435c2f1c4463d1416f6f9
[root@localhost ~]# docker run --name web3 -d -p 80 -v /htdocs:/usr/local/apache2/htdocs httpd
2da85061d406c8cf5cbe061fb42a5e58257816dcd9eaa7db82b7ce951305ae39

查看当前主页:

[root@localhost ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
2da85061d406        httpd               "httpd-foreground"   6 seconds ago       Up 5 seconds        0.0.0.0:32770->80/tcp   web3
fe50f6b90793        httpd               "httpd-foreground"   11 seconds ago      Up 10 seconds       0.0.0.0:32769->80/tcp   web2
b004d4df2fe4        httpd               "httpd-foreground"   20 seconds ago      Up 19 seconds       0.0.0.0:32768->80/tcp   web1

[root@localhost ~]# curl 127.0.0.1:32768
hug
[root@localhost ~]# curl 127.0.0.1:32769
hug
[root@localhost ~]# curl 127.0.0.1:32770
hug

修改 volume 中的主页文件,再次查看:

[root@localhost ~]# echo "hhhhhhhhhh" > /htdocs/index.html 
[root@localhost ~]# curl 127.0.0.1:32769
hhhhhhhhhh
[root@localhost ~]# curl 127.0.0.1:32768
hhhhhhhhhh
[root@localhost ~]# curl 127.0.0.1:32770
hhhhhhhhhh

用volume container共享数据

volume container是专门为其他容器提供volume 的容器。它提供的卷可以是 bind mount ,也可以是 docker managed volume。

创建一个 volume container:

[root@localhost ~]# docker create --name vc_data -v /htdocs:/usr/local/apache2/htdocs -v /other/userful/tools httpd
f5192fe00a8932df333ee2eafb0ff8797b053329e5e236bc29975f848d9a0b56

将容器命名为 vc_data。注意这里执行的是docker create命令,这是因为volume container 的作用只是提供数据,它本身不需要处于运行状态。
容器 mount 了两个 volume:

1.bind mount,存放web server的静态文件
2.docker managed volume,存放一些实用工具

通过docker inspect 查看 volume

[root@localhost ~]# docker inspect  vc_data  | grep Destina
                "Destination": "/usr/local/apache2/htdocs",
                "Destination": "/other/userful/tools",

其他容器可以使用 - -volumes-from 使用 vc_data这个 volume container:

[root@localhost ~]# docker run --name web1 -d -p 80  --volumes-from  vc_data  httpd
aab5751a7bb371f5deffef3ad98bcee95d87dcc69c08525eaec6b3417852b381
[root@localhost ~]# docker run --name web2 -d -p 80  --volumes-from  vc_data  httpd
a9bf189425bd4e258750fcc7b81be1e86a7184971cb49303ddf5dad579b6c676
[root@localhost ~]# docker run --name web3 -d -p 80  --volumes-from  vc_data  httpd
bdd982b6d819fab3cfd8791f5058d8f02f875507cc98030309a9707d36f35046

三个httpd容器都使用了 vc_data,查看都有哪些volume:

[root@localhost ~]# docker inspect web1 | grep Destina
                "Destination": "/usr/local/apache2/htdocs",
                "Destination": "/other/userful/tools",

验证共享效果:

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED              STATUS              PORTS                   NAMES
bdd982b6d819        httpd               "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:32773->80/tcp   web3
a9bf189425bd        httpd               "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:32772->80/tcp   web2
aab5751a7bb3        httpd               "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:32771->80/tcp   web1
[root@localhost ~]# echo "this this hsith" > /htdocs/index.html 
[root@localhost ~]# curl 127.0.0.1:32771
this this hsith
[root@localhost ~]# curl 127.0.0.1:32772
this this hsith
[root@localhost ~]# curl 127.0.0.1:32773
this this hsith

volume container的特点:

1.与bind mount相比,不必为每个容器指定 host path,所有path都在volume container中定义好了,容器只需与volume container关联,实现了容器与host的解耦。

2.使用volume container的容器其mount point是致的, 有利于配置的规范和标准化,但也带来定的局限, 使用时需要综合考虑。

另-种在容器之间共享数据的方式是data-packed volume container。

data-packed volume container

volume container 的数据在host里,有没有办法将数据完全放到volume container中,同时又能与其他容器共享呢?
当然可以,通常我们称这种容器为data-packed volume container.其原理是将数据打包到镜像中,然后通过docker managed volume共享。

我们用Dockfile构建镜像:

[root@localhost /]# mkdir datapacked
[root@localhost /]# cd datapacked/
[root@localhost datapacked]# ls
[root@localhost datapacked]# cat Dockerfile
FROM httpd
ADD htdocs  /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs

ADD将静态文件添加到容器目录/usr/local/apache2/htdocs.。VOLUME 的作用与-v等效,用来创建docker managedvolume, mount point为/usr/ocal/apache2/htdocs,因为这个目录就是ADD添加的目录,所以会将已有数据拷贝到volume中。

build 新镜像

[root@localhost datapacked]# mv /htdocs/ .
[root@localhost datapacked]# docker build -t data .

用新镜像创建 data-packed volume container:

[root@localhost datapacked]# docker create --name vc_data2 data
345255edfd3dfb6368d3c3ad932dd6aadcffd46a00cacc6f2bf849d69a8f885c

因为在Dockerfile中使用了VOlUME指令,这里就不需要指定volume的mount point,启动容器并使用data-packed volume container。

[root@localhost datapacked]# docker run -d -p 8000:80 --volumes-from vc_data2 httpd
dca8789bd56ea79574866ac115a352d9466708eb0abd6ade0129df0b5ff550bd
[root@localhost datapacked]# curl 127.0.0.1:8000
this this hsith

容器能够正确读取volume中的数据。data-packed volume container是自包含的,不依赖host提供数据,具有很强的移植性,非常适合只使用静态数据的场景,比如应用的配置信息、web server的静态文件等,

volume生命周期管理

Data Volume中存放的是要的应用数据,如何管理volume对应用至关重要。前面我们主要关注的是volume的创建、共享和使用。

备份

因为volume实际上是host文件系统中的目录和文件,所以volume的备份实际上是对文件系统的备份。所有的本地镜像都存在host的/myregistry目录中,我们要做的就是定期备份这个目录。

恢复

volume的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到/myregistry就可以了。

迁移

如果我们想使用更新版本的Registry,这就涉及到数据迁移,方法是:

  1. docker stop当前Registry容器。
  2. 启动新版本容器并mount原有volume.

docker run -d -P 0005000 -V /myregisty:/ar/lib/registry registry:latest

当然,在启用新容器前要确保新版本的默认数据路径是否发生变化。

销毁

可以删除不再需要的volume, volume 删除后数据是找不回来的。

docker不会销毁bind mount,删除数据的工作只能由host负责。对于docker managed volume,在执行docker rm删除容器时可以带上-V参数,docker 会将容器使用到的volume一·并删除, 但前提是没有其他容器mount该volume,目的是保护数据。
如果删除容器时没有带-v这样就会产生孤儿volume,好在docker提供了volume 子命令可以对docker managed
volume进行维护。请看下面的例子:
容器bbox使用的docker managed volume可以通过docker volume Is查看到。

删除孤儿volume:

[root@localhost ~]# docker volume rm 3b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff463b1a7628fe1772d91497ad2a518b1b1637ea51f26a70f9415d477c539739ff46
[root@localhost ~]# docker volume rm  $(docker volume ls -q

Docker 存储卷

标签:运行   pat   版本   tap   user   c11   永久   堆叠   信息   

原文地址:https://blog.51cto.com/14833298/2500920

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!