本文由作者邹珍珍授权网易云社区发布。

本文主要介绍Docker的存储管理。Docker拥有镜像分层,写时复制机制以及内容寻址存储等特征,为了支持这些特征,Docker设计了一套镜像元数据管理机制来管理镜像元数据。另外,为了能够让Docker容器适应不同平台不同应用场景对存储的要求,Docker提供了各种基于不同文件系统实现的存储驱动来管理实际的镜像文件。下面就详细介绍镜像元数据管理和存储驱动。

另外,本文最后简单介绍了Docker数据卷以及数据卷的基本操作。

一、Docker镜像元数据管理

Docker镜像在设计上将镜像元数据和镜像文件的存储完全分隔。在管理镜像层元数据时,采用repository,image,layer三层次。Docker分层存储镜像,repository和image这两类元数据时没有物理上的镜像文件与之对应,只有layer这种元数据时有的。(通俗讲,我们拉取的镜像就是分层存的镜像文件,每个镜像层可以是不同的文件系统。前面的三类元数据就是些镜像的信息和镜像层之间的关系说明。)

1. Repository元数据

在本地的持久化文件存放在/var/lib/docker/image/{graphdriver} /repositories.json

*注意:显示了所有repository的镜像名,每个repository下的版本镜像名字:tag以及镜像ID(采用SHA256算法)。上图可见,我的云主机上graphdriver是devicemapper,只有三个镜像。本机上的graphdriver存储驱动可以在/var/lib/docker/下查看

2. Image元数据

在本地的持久化文件存放在/var/lib/docker/image/{graphdriver} /imagedb/content/sha256/{imageid}

*注意:刚刚在Repository的文件中只看到了三个镜像,但在这里确看到了六个,这是因为前面的zzz/Ubuntu:1.0是我用dockerfile自己构建的镜像,在构建镜像的过程中的形成的中间层镜像也会被保存下来。使用docker run这个中间层镜像id是可以运行一个容器,从而查看每一步构建镜像后的实际状态,提供调试构建过程的能力。

另外,image元数据中包括了镜像架构,操作系统,默认配置,构建该镜像的容器ID以及rootfs等等。内容较多就不截图了。

3. Layer元数据

只读层的存储路径/var/lib/docker/image/{graphdriver} /layerdb/sha256/{chainID}

*注意:理所当然layer的元数据比image多,因为一个image对应多个镜像层layer。上图是只读层,每个只读层主要存索引该镜像层的chainID、该镜像层的校验码diffID,父镜像层parent,已经存储驱动存储该镜像层文件的cacheID,镜像层大小size。

可读写层(容器层)的存储路径/var/lib/docker/image/{graphdriver} /layerdb/mounts/{containerid}

二、存储驱动GraphDriver

Docker引擎1.12版本中,GraphDriver有以下几种:vfs、aufs、overlay、overlay2、btrfs、zfs、devicemapper和windows

A.GraphDriver必须执行什么操作?也就是它的功能是什么?

GraphDriver主要定义了ProtoDriver和Driver接口。主要实现功能(总共有12个方法,以下没有全部介绍):

(1)提供(计算)差别和改动相关的方法:都是比较指定镜像层与它的父镜像的差异,根据不同的方法返回不同的信息,比如Diff()将改动的文件打包;Chnages()是返回差异列表等等。

(2)Create( )创建镜像层:镜像包含多个分层(layer),这些分层有存在父级子级的关系。利用graphdriver驱动,采用最适合该文件系统实现中类似联合和写时复制(union+CoW-like)的叠层技术,来保存这些分层和它们之间的关系。要处理这些分层镜像的创建和解开(un-tar)操作,以及将镜像解开的内容放到创建的位置,会用到graphdriver的Create和ApplyDiff接口;

(3)remove( )删除镜像层:当镜像从本地缓存删除的时候需要执行相反的操作,“分层仓库”会调用graphdriver的Remove接口来将分层的内容从系统中删除;

(4)Get( )返回指定ID层的挂载点的绝对路径:容器需要运行时,在容器启动之前这些必须被组装成可运行的根文件系统。graphdriver的Get方法会被调用并带上一个特定的标识符,此时根据graphdriver特定文件系统的实现,需要根据父级连接关系遍历并且使用该文件系统提供的相应技术来将分层堆叠成一个单独的挂载点,并创建可写的上层或者顶部分层来满足容器更改文件系统的需要。

(5)put( )释放一个层使用的资源:告知graphdriver,某挂载的资源没有用了,并在绝大多数的场景下卸载相关的层。

B. 为什么一个Image运行多个Container?以AUFS存储驱动为例进行说明。

AUFS核心概念:将多个目录合并成一个虚拟文件系统,成员目录称为虚拟文件系统的一个分支(branch)。

*注意:上图把 /tmp, /var, /opt三个目录联合挂着到 /aufs目录下,则 /aufs目录可见 /tmp, /var, /opt目录下的所有文件。而每个成员目录,则称为虚拟文件系统的一个branch。

每个branch可以指定 readwrite/whiteout‐able/readonly权限,只读(ro),读写(rw),写隐藏(wo。一般情况下,aufs只有最上层的branch具有读写权限,其余branch均为只读权限。

Docker镜像(Image)是由一个或多个AUFS branch组成,并且所有的branch均为只读权限。简单来说,AUFS所有robranch按照一定顺序堆积构成Docker Image镜像。

在运行容器的时候,创建一个AUFS branch位于image层之上,具有rw权限,并把这些branch联合挂载到一个挂载点下。这就是Docker能够一个镜像运行多个容器的原理所在。

*注意:Image有3个目录位于 /var/lib/docker/aufs/diff/文件夹内,当基于该Image创建容器时,创建一个容器运行目录,同样位于/var/lib/docker/aufs/diff/目录下,并使用aufs联合挂载Image目录和Container目录到 /var/lib/docker/aufs/mnt/目录下。创建多个容器时,只需创建多个容器运行目录,使用aufs把容器运行目录挂载在Image目录之上,即实现一个Image运行多个Container。

C.容器文件读写与删除如何实现?

当容器需要修改一个文件,而该文件位于低层branch时,顶层branch会直接复制低层branch的文件至顶层再进行修改,而低层的文件不变,这种方式即是CoW技术(写复制),AUFS默认支持Cow技术, 从而保证镜像层数据的完整性和复用性

当容器删除一个低层branch文件时,只是在顶层branch对该文件进行重命名并隐藏,实际并未删除文件,只是不可见,这种方式即AUFS的whiteout(写隐藏)。

-----------------------------------------------------------分割线-----------------------------------------------------------

Docker数据卷

在默认情况下,当用户退出容器而容器中又没有非守护进程在运行时,容器会进入关闭状态,同时,数据的修改会保留在最上层的可写文件系统内。当用户需要重新开启一个容器时,是无法访问原来所做的修改的,而是恢复到镜像的初始化状态。为了解决数据持久化的问题,Docker提供了数据卷。

关于数据卷的操作比较好理解,以下是关于数据卷一些基本操作的链接:

http://www.heblug.org/chinese_docker/userguide/dockervolumes.html

免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

更多网易技术、产品、运营经验分享请访问网易云社区

相关文章:
【推荐】 用双十一的故事串起碎片的网络协议(下)

Docker之存储管理的更多相关文章

  1. docker存储管理及实例

    一.Docker存储概念 1.容器本地存储与Docke存储驱动 容器本地存储:每个容器都被自动分配了内部存储,即容器本地存储.采用的是联合文件系统.通过存储驱动进行管理. 存储驱动:控制镜像和容器在 ...

  2. Docker 镜像之存储管理

    笔者在<Docker 镜像之进阶篇>中介绍了镜像分层.写时复制以及内容寻址存储(content-addressable storage)等技术特性,为了支持这些特性,docker 设计了一 ...

  3. 005.Docker存储管理

    一 Docker volume形态 因为Docker 采用 AFUS 分层文件系统时,文件系统的改动都是发生在最上面的容器层,在容器的生命周期内,它是持续的,包括容器在被停止后.但是,当容器被删除后, ...

  4. docker存储管理

    Docker 镜像的元数据 repository元数据 repository在本地的持久化文件存放于/var/lib/docker/image/overlay2/repositories.json中 ...

  5. 云计算Docker全面项目实战(Maven+Jenkins、日志管理ELK、WordPress博客镜像)

    2013年,云计算领域从此多了一个名词“Docker”.以轻量著称,更好的去解决应用打包和部署.之前我们一直在构建Iaas,但通过Iaas去实现统一功  能还是相当复杂得,并且维护复杂.将特殊性封装到 ...

  6. Swarm 如何存储数据?- 每天5分钟玩转 Docker 容器技术(103)

    service 的容器副本会 scale up/down,会 failover,会在不同的主机上创建和销毁,这就引出一个问题,如果 service 有要管理的数据,那么这些数据应该如何存放呢? 选项一 ...

  7. 聊聊Docker

    为什么是Docker 进入21世纪,继互联网之后,云计算开始大放异彩.云计算是互联网发展后期的必然方向,反过来,云计算也进一步推动了互联网的发展.云计算模式最关键的突破就是资源使用方式的改变. 云计算 ...

  8. docker组件介绍

    一.Docker Client and Daemon(docker egine docker 引擎) docker是一个客户端工具,作用是发送 用户的请求给 dockerd 安装路径: /usr/bi ...

  9. centos7下安装docker(24docker swarm 数据管理)

    service的容器副本会scal up/down,会failover,会在不同的主机上创建和销毁,这就引出一个问题,如果service有数据,那么这些数据该如何存放呢? 1.打包在容器中: 显然不行 ...

随机推荐

  1. [leetcode]416. Partition Equal Subset Sum分割数组的和相同子集

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  2. Message: u'$ is not defined' ; Stacktrace

    status.html <html> <head> <meta http-equiv="content-type" content="tex ...

  3. Spring框架整合JUnit单元测试

    1. 为了简化了JUnit的测试,使用Spring框架也可以整合测试 2. 具体步骤 * 要求:必须先有JUnit的环境(即已经导入了JUnit4的开发环境)!! * 步骤一:在程序中引入:sprin ...

  4. Nginx+Keepalived实现站点高可用[z]

    http://segmentfault.com/a/1190000002881132

  5. Codeforces 709B 模拟

    B. Checkpoints time limit per test:1 second memory limit per test:256 megabytes input:standard input ...

  6. makeuque

    http://blog.csdn.net/10km/article/details/49867479

  7. 如何在c语言中源文件调用另一个源文件的函数

    在源文件A1.c中调用A2.c 中的函数有两种方法: 1.在A2.c中有完整的函数定义,在A1.c中添加一下要用到的函数原型(声明)就可以了,例如:在A2.c中:有函数void A2(){...};在 ...

  8. 01 Linux 网络配置和克隆

    Linux 网络配置和克隆 一.配置 Linux 网络 当在 VMware 中安装完 Linux 以后需要通过一些网络配置才能使 Linux 能够连能网络: 首先如果是在虚拟机上安装的 Linux 必 ...

  9. wcf服务契约代理链

    意图:为了是客户端代理呈现出面向对象的多态的特征 a. 服务端 .契约 实现了契约的继承这个在服务端是一点问题没有,因为oprationcontract可以继承,虽然DataContract不能实现继 ...

  10. part1:7-Linux网络配置

    1.虚拟机(Vmware)网络配置 VMware虚拟机对于不同的网络环境提供了三种网卡工作模式: Bridged:网桥模式: 在桥接模式下,计算机A充当路由器与虚拟机之间的“桥”,虚拟机通过计算机A的 ...