理解镜像、容器和存储驱动

为了更有效地使用存储驱动,你必须理解Docker如何创建和存储镜像。接下来,需要理解容器是如何使用这些镜像的。最后,你需要一个对镜像和容器操作者都需要的技术简介。

镜像和图层layers

每一个Docker镜像都参考了一系列的只读层,这些层代表着文件系统的区别。层级是从底层开始,逐一建立组成容器的root文件系统。下面的图显示了Ubuntu镜像有4层:

Docker的存储驱动是负责堆放这些层级并且提供一个统一的视图。

当你创建一个新的容器,你会在底层栈上加入一个新的、稀疏的、可写的层。这个层级通常被称为“container layer”。容器运行中所有的变化----例如写入一个新文件,修改已经存在的文件、删除文件---都是写入到这个层级中。下面的图显示了一个基于Ubuntu的容器。

内容寻址存储

Docker 1.10版本引入了一个新的内容寻址存储模型。这是一个全新的方式在磁盘上定位镜像和数据层。原先版本中,镜像和数据层相互引用,并且使用一个随机生成的UUID存储。在新的模型中被替换成了一个安全的内容哈希。

新的模型改进了安全性,提供了一个内置的方式避免ID冲突,并且在pull、push、load、save操作中保证了数据完整性。它也可以使得不是来自一个bulid的镜像自由引用他们的层级。

下面的图中显示了Docker 1.10版本的更新。

可以看到的是,所有的镜像层级IDs是加密的哈希值,但是镜像ID仍旧是一个随机生成的UUID。

关于新版本有几点需要考虑:

1.       迁移已经有的镜像

2.       镜像和层级文件系统结构

(PS:忽略迁移过程,全部为最新版本)

容器和层级

容器和镜像的主要区别之一是最上层的可写层。容器所有写入/修改操作都会存储在这个可写层中。当一个容器删除时,这个可写层同时也被删除。底层的镜像仍旧保持不变。

因为每个容器都有他自己的稀疏可写层,并且所有容器的变更都会写入到这个层中,这意味着多个容器可以共享一个底层的镜像并且容器有自己的数据。下面的图显示了多个容器使用了同一个镜像。

copy-on-write策略

共享是优化资源的一个很好的方式。人们在日常生活中会本能的做这件事情。例如,两个双胞胎Jane和Joseph参加一个不同老师不同时间代数学课程,他们就可以共享练习本。现在假设Jane有一个作业,需要完成这本书第11页的家庭作业。这时候,Jane抄写了第11页,完成了作业并且上交了他的副本。原先的练习册并没有发生变化并且只有Jane有一份已经改变的11页。

Copy-on-write是一个类型共享和复制的策略。在这个策略中,需要相同数据的容器会共享他们所需的数据,不会每容器都保存一份。在某些时候,如果一个进程需要修改或者写入数据,只有这个时候操作系统才会复制一份数据给这个进程使用。只有这个进程对需要修改的数据副本有访问权限,其他所有进程继续使用原始数据。

Docker的镜像和容器都使用了copy-on-write技术。Cow策略优化了镜像使用的存储空间和容器启动花费的时间。下个章节将会看到镜像和容器是如何利用COW。

共享提升小镜像

这个章节将关注镜像层级和cow技术。所有在同一个主机本地存储镜像和容器层级都被存储驱动管理。在Linux系统通常位于/var/lib/docker/。

当进程pull和push操作时,Dcoker客户端会报告镜像的层级。下面的命令是下载docker镜像的输出:

$ docker pull ubuntu

Using default tag: latest

latest: Pulling from library/ubuntu

43db9dbdcb30: Pull complete

85a9cd1fcca2: Pull complete

c23af8496102: Pull complete

e88c36ca55d8: Pull complete

Digest: sha256:7ce82491d6e35d3aa7458a56e470a821baecee651fba76957111402591d20fc1

Status: Downloaded newer image forubuntu:latest

从这个输出可以看到实际上下载了4个镜像层级。每行都列出了一个镜像层级和他的UUID或者加密的哈希。这4个层级组成了ubuntu镜像。

每个层级都在主机本地存储有自己的目录存放。

在Docker 1.10之前版本,每个层级存放在以镜像层级ID命名的文件夹中。然而,Dokcer 1.10版本之后下载的镜像不会这样存储。例如,下图显示了版本1.9.1从Docker Hub下载一个镜像后,与之对应的主机文件夹情况:

$ docker pull ubuntu:15.04

15.04: Pulling from library/ubuntu

47984b517ca9: Pull complete

df6e891a3ea9: Pull complete

e65155041eed: Pull complete

c8be1ac8145a: Pull complete

Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e

Status: Downloaded newer image forubuntu:15.04

$ ls /var/lib/docker/aufs/layers

47984b517ca9ca0312aced5c9698753ffa964c2015f2a5f18e5efa9848cf30e2

c8be1ac8145a6e59a55667f573883749ad66eaeef92b4df17e5ea1260e2d7356

df6e891a3ea9cdce2a388a2cf1b1711629557454fd120abd5be6d32329a0e0ac

e65155041eed7ec58dea78d90286048055ca75d41ea893c7246e794389ecf203

注意上面四个目录的名称是符合层级ID的。现在对比下在Docker 1.10版本以上的区别。

$ docker pull ubuntu:15.04

15.04: Pulling from library/ubuntu

1ba8ac955b97: Pull complete

f157c4e5ede7: Pull complete

0b7e98f84c4c: Pull complete

a3ed95caeb02: Pull complete

Digest:sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e

Status: Downloaded newer image forubuntu:15.04

$ ls /var/lib/docker/aufs/layers/

1d6674ff835b10f76e354806e16b950f91a191d3b471236609ab13a930275e24

5dbb0cbe0148cf447b9464a358c1587be586058d9a4c9ce079320265e2bb94e7

bef7199f2ed8e86fa4ada1309cfad3089e0542fec8894690529e4c04a7ca2d73

ebf814eccfe98f2704660ca1d844e4348db3b5ccc637eb905d4818fbfb00a06a

可以查看到四个目录的名称与层级的ID并不符合。

尽管在版本1.10与之前版本之间存在镜像管理的区别,但是所有版本的Docker都可以允许镜像共享层级。例如,如果你进行pull一个镜像和其他已经下载的镜像共享部分层级,Docker会知道这个信息并且只会下载本地没有的部分。当这个镜像下载完成,这两个镜像会共享同样的镜像层级。

你可以自己举例说明。从刚才下载的ubuntu镜像开始,对他进行操作产生一个新的镜像。其中一个方法是使用Dockerfile和docker build。

下面过程略。

复制使得镜像更有效

在之前的章节你可以了解到容器是一个Docker镜像加上一个稀疏可写的容器层。下面的图显示了一个基于ubuntu镜像的容器。

容器中所有的写操作都存放在稀疏可写的容器层级中。其他层级是只读的镜像层级并且无法修改。这意味着多个容器可以安全地共享一个底层镜像。下面的图显示了多个容器共享一个ubuntu镜像。每个容器都有自己的可写层,但是他们都共享一个ubuntu镜像。

当镜像中的一个已经存在的文件被修改了,Dokcer使用存储驱动进行一次copy-on-write操作。具体操作实现细节由存储驱动决定。对于aufs和Overlay存储驱动,copy-on-write操作如下所示:

l   搜索整个镜像层级,查找需要更新的文件。这个进程从最高、最新的层级开始直到最底层。

l   对第一个找到的文件进行一个copy-up操作。Copy-up操作会把文件拷贝到容器自己的稀疏可写层。

l   在稀疏可写层修改这个文件。

Btrfs、ZFS和其他驱动copy-on-write都不相同。你可以在后续的文档中获取到关于这些驱动的具体描述。

写入很多数据的容器相比没有写入多少数据的容器会消耗更多的空间。这是因为多数的写入操作会在容器最高层的稀疏可写层,消耗更多的空间。如果容器需要写入很多数据,你需要考虑使用数据卷。

一个copy-up的操作会导致显著的性能瓶颈。这个瓶颈决定于使用的存储驱动。然而,大的文件、更多的层级和更深的目录树可能会有更多影响。幸运的是,这个操作仅会发生在特定文件第一次被修改的时候。对同一个文件后续的操作不会导致copy-up操作,可以直接在容器层直接操作已经复制的文件。

让我们来看下如果通过changed-ubuntu镜像启动5个容器的情况:

1.在一个Docker主机上,使用dockerrun命令5次:

这个操作会基于changed-ubuntu镜像启动5个容器。随着容器创建,Docker会自动增加一个可写的层级并且分配一个随机的UUID。这会返回给docker run命令。

2.运行docker ps命令确认5和容器都在运行

输出显示5个正在运行的容器,他们共享一个镜像。每个容器的CONTAINER ID是创建时UUID的一部分。

3. 列出本地存储区域的内容:

Docker的copy-on-write策略不仅减少了容器使用的空间,也会减少启动容器的时间。在启动时,Docker仅需要为每个容器创建一个稀疏可写层。下面的图显示了5个容器共享一个只读的镜像。

数据卷和存储驱动

当一个镜像被删除后,任何没有写入到数据卷的数据会随着镜像的删除而删除。

一个数据卷是Docker主机文件系统上的一个目录或文件直接挂载到一个容器。数据卷是不受存储启动的控制。对数据的读写会绕开存储驱动,直接在主机层操作。你可以挂载任意数量的数据卷到容器中。多个容器也可以共享一个或者多个数据卷。

下面的图显示了一个Docekr主机运行了两个容器。每个容器有存在自己的寻址空间,位于主机的本地存储/var/lib/docker/…目录。这里也有主机也有一个共享的/data目录作为容器的数据卷,mount到两个容器中。

数据卷主机本地存储的一部分,是不受到存储驱动控制的。当一个容器被删除了,任何存储在数据卷的数据都会持久存放在Docker主机上。

Summary

Docker的镜像是多个只读的层级组成,并且多个只读的层级是可以被多个镜像共享的,可以节省空间。

Docker容器在启动时,会在镜像上创建一个稀疏可写层,并使用copy-on-write策略进行更新。Cow的实现由存储驱动具体实现,常见的有aufs、device mapper等。

数据卷会跳过存储驱动,不受到存储驱动影响,效率会更好。

理解镜像、容器和存储驱动相关推荐

  1. Docker 容器文件存储驱动 Overlay2

    码字不易,转载请注明出处!! 写在前面 Docker 文件存储驱动有很多种,比如 overlay2.aufs等,可以通过命令 docker info 查看: > # docker info &g ...

  2. docker配置阿里云镜像加速并更改镜像和容器的存储位置及常见的docker bug解决方法

    配置阿里云镜像加速 使用docker容器管理服务,总结下来就三个重要概念: 镜像,容器,数据卷.在之前的博文中我们已经讲述了如何在linux服务器上安装docker,并运行docker服务了. 这篇文 ...

  3. 镜像的存储和存储驱动

    什么是bootfs? bootfs就是内核引导器(引导加载内核)和内核.bootfs主要包含bootloader和kernel,bootloader主 要是引导加载kernel,Linux刚启 动时会 ...

  4. 10张图带你深入理解Docker容器和镜像--云平台技术栈07

    导读:之前发布了云平台技术栈(ps:点击可查看),本文主要说一下其中的Docker! 翻译:杨润青 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image ...

  5. 10张图带你深入理解Docker容器和镜像

    本文用图文并茂的方式介绍了容器.镜像的区别和Docker每个命令后面的技术细节,能够很好的帮助读者深入理解Docker. 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(containe ...

  6. Docker / 深入理解的容器和镜像

    这篇文章希望能够帮助读者深入理解 docker 的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 零.概览 当我对 docker 技术还是 ...

  7. DockerONE 干货 深入理解Docker容器和镜像

    这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 当我对Docker技术还是一知半解的时候,我 ...

  8. 10 张图带你深入理解Docker容器和镜像

    此文中部分信息.图片需要 fan qiang , 如果未能正常显示,文末有原文连接 . [Kubernetes培训通知]DockOne将会于2018年5月18日在上海举办Kubernetes技术培训, ...

  9. Docker--10张图带你深入理解Docker容器和镜像

    这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 当我对Docker技术还是一知半解的时候,我 ...

最新文章

  1. Java高危漏洞被再度利用 可攻击最新版本服务器
  2. android将发送短信写入发件箱
  3. 【bzoj4025】二分图 LCT
  4. 鸿蒙os能超越ios吗,鸿蒙OS对比iOS,华为再次“超越”,流畅度大幅领先苹果!...
  5. 容器编排技术 -- Kubernetes 中查看Pods和Nodes
  6. bzoj2821 作诗(Poetize)分块+二分
  7. ckc交易什么意思_1379ip0在股市是什么意思,600875东方电气股票,股市交易手续费计算...
  8. 9.jsonp的实现原理
  9. 手把手,快速搭建 Cocos2d-HTML5 开发调试环境
  10. SQL 单表查询多个计算的值
  11. [转载] Python 快速入门实战教程
  12. FPGA内部资源结构——以Altera CycloneⅣ 为例
  13. 4G边缘计算工业路由器与传统4G工业路由器的区别
  14. Xcode自动编译、打包、上传到蒲公英应用分发平台
  15. 公务员没考上……我做了投资
  16. 【3Dprinter】3D打印机机型结构 UM、I3、Hbot等的简单介绍
  17. Oracle常见问题一千问
  18. 图鉴| IT男什么时候最虚伪?
  19. 哈工大pyltp安装和使用方法
  20. Google Maps基础及实例解析

热门文章

  1. vue.js毕业设计,基于vue.js前后端分离教室预约系统(H5移动项目) 开题报告
  2. setInterval()与setTimeout() 详细
  3. 解决android上WIFI提示“未检测到任何互联网连接,因此不会自动重新连接“
  4. Lect6_Value_Function_Approximation
  5. 微信小程序富文本标签 rich-text 图片自适应大小问题
  6. 【渝粤题库】国家开放大学2021春2196社会调查研究与方法题目
  7. 移动WEB各种布局开发笔记
  8. ceisum 加载geojson,使用 Cesium 动态加载 GeoJSON 数据
  9. 老毛桃 装WIN 10 系统
  10. pair及pair在vector中的使用