Docker存储
Docker为容器提供了两种存放数据的资源
1. storage driver管理的镜像层和容器层
2. Date Volume
storage driver
容器由最上面一个可写的容器层和若干只读的镜像层组成,容器的数据就存在这些层中。这种分层结构最大的特点是Copy-on-Write
1. 新数据会直接存放在最上面的容器层
2. 修改现有数据会先从镜像层复制文件到容器中,再在容器层修改并保持,镜像层的数据不会发生改变
3. 若多个层中有命名相同的文件,用户只能看到最上面一层的文件
Date volume之bind mount
Date volume的特点
1. Date volume是目录或文件,而非没有格式化的磁盘
2. 容器可以读写volume中的数据
3. volume数据可以被永久保存,即使使用它的容器已经销毁
docker提供两种类型的volume:bind mount和docker managed volume
bind mount是将host上已经存在的目录或文件mount容器
例如docker host上有目录$HOME/test
通过-v将其mount到httpd容器
-v的格式为<host path>:<container path>。/usr/local/apache2/test就是apache server存放静态文件的地方。由于/usr/local/apache2/test已经存在,原有数据会被隐藏起来,取而代之的是host $HOME/test/ 中的数据,这与linux mount命令的行为是一致的。
下面我们进入到容器里面去查看mount过去的目录及其文件
这与host下的文件内容一致,现在我们在host中对文件内容进行更新,再进入容器查看修改后的文件,由结果可以看出,在host中修改了index.html文件的内容,容器中文件的内容也跟着被修改
也可以使用参数来修改文件的权限,比如下面的例子使用ro将文件设置为只读,容器不能对该文件进行修改,只有在host里面才有权限修改文件
使用bind mount单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录。在上面的例子中,我们将html文件加到apache中,同时也保留了容器原有的数据。
使用单一文件有一点要注意:host中的源文件必须要存在,不然会当作一个新目录bind mount给容器。
mount point有很多应用场景,比如我们可以将源代码目录mount到容器中,在host中修改代码就能看到应用的实时效果。再比如将mysql容器的数据放在bind mount里,这样host可以方便地备份和迁移数据。
bind mount不足的地方:bind mount需要指定host文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他host,而该host没有要mount的数据或者数据不在相同的路径时,操作会失败。
docker managed volume
docker managed volume与bind mount最大的区别是不需要指定mount源,指明mount point就行了,还是以httpd容器为例,创建容器后并用inspect来查看mount源
docker manages volume的创建过程
1. 容器启动时,简单告诉docker“我需要一个volume存放数据,帮我mount到目录/abc”
2. docker在 /var/lib/docker/volume中生成一个随机目录作为mount源
3. 如果/abc已存在,则将数据复制到mount源
4. 将volume mount到/abc
容器与host共享数据
有两种类型的data volume,它们都可以实现在容器与host间共享数据
对于bind mount:直接将要共享的目录mount到容器,可以参照前面的例子
docker managed volume要麻烦些。由于volume位于host中的目录,是在容器启动时才生成,所以需要将共享数据copy到volume中,可以用docker cp在容器与host之间进行文件拷贝
容器之间共享数据
第一种实现方法是将共享数据放在bind mount中,然后再mount到多个容器。先创建三个httpd容器组成web server集群,它们使用相同的html文件,具体操作如下
1. 将HOME/test mount到三个httpd容器
2. 查看当前主页内容
3. 修改volume中的主页文件,再次查看并确认所有容器文件都使用了新的主页
另一种方法是用volume container共享数据,下面创建一个volume container
这里执行的是docker create命令,因为volume container的作用只是提供数据,它本身不需要处于运行状态。容器mount了两个volume
1. bind mount,存放web server静态文件
2. docker managed volume,存放一些实用工具(这里为空,只是为了演示)
通过docker inspect vc_date来查看这两个volume
其他容器可以通过--volumes-from使用vc_date这个volume container
三个容器都使用了vc_date,以web4为例查看它的volume
web4容器使用的是vc_date的volume,而且mount point都是一样的,验证一下数据共享结果,由结果可以看出三个容器已经成功共享了volume container的volume
data-packed volume container
可以将数据完全放在volume container中,与其他容器共享。其方法是将数据打包到镜像,然后通过docker managed volume共享
用Dockerfile构建镜像,其中ADD将静态文件添加到容器目录,VOLUME的作用于-v等效,用来创建docker manage volume
build新镜像datapacked
用新镜像创建data-packed volume container
因为在Dockerfile中使用了VOLUME指令,这里就不需要指定volume的mount point了。启动httpd容器并使用data-packed volume container
容器能够正确读取volume中的数据,data-packed volume container是自包含的,不依赖于host提供数据,具有很强的移植性,非常适合只用静态数据的场景,比如web server静态文件
volume生命周期管理
备份
前面搭建了一个本地Registry,并可以通过本地搭建的Registry来运行容器。所有的本地镜像都存在host的 /myregistry目录下,我们要定期备份这个目录
恢复
volume的恢复很简单,如果数据损坏了,直接用之前备份的数据copy到/myregistry下即可
迁移
1. docker stop当前Registry容器
2. 启动新版本容器并mount原有volume
docker run -d -p 5000:5000 -v /myregistry:/usr/lib/registry registry:lastest
销毁
docker不会销毁bind mount,删除数据只能在host上执行。对于docker managed volume,在执行docker rm时可以带上-v参数,docker会将容器使用到的volume一并删除,但前提是没有其他容器mount该volume。也可以用docker volume ls来查看当前的volume,docker volume rm来删除遗留下来的volume。如果想要批量删除遗留的volume,可以使用以下命令
docker volume rm $(docker volume ls -q)