docker基础-镜像

docker基础-镜像

docker公司在实现docker镜像时并没有沿用以前只做roots的标准流程,而是做了一个小小的创新:

docker在镜像的设计中引入了层(layer)的概念,也就是说,用户制作镜像的每一步操作,都会生成
一个层,也就是一个增量的roofs。

当然,这个想法不是凭空臆造出来的,而是用到了一种叫做联合文件系统(union file system)的能力。

union file system 也叫unionfs,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下,比如,我限制有两个目录A和B,它们分别有两个文件。

# tree
.
├── A
│  ├── a
│  └── x
└── B
  ├── b
  └── x

然后使用联合挂载的方式,将这两个目录挂在到一个公共的目录C上。

# mkdir C
# mount -t aufs -o dirs=./A:./B none ./C

这时,我再查看目录C目录的内容,就能看到目录A和B下的文件被合并到了一起.

tree ./C
./C
├── a
├── b
└── x

可以看到,在合并后的C目录里,有a、b、x三个文件,并且x文件只有一份,这就是“合并”的含义,此外,如果你在目录C里对a、b、x文件做修改,这些修改也会在对应的目录A、B中生效。

那么,在docker项目中,又是如何使用这种unionfs呢?

我的环境是ubuntu 和docker ce,这对组合牧人使用的是auFS这个联合文件系统的实现,可以通过命令docker info查看dockre信息。

aufs的全程是another unionfs,后来改名alternative unionfs,再后来又改名advance unionfs,从这些名字里可以看出两个事实:

1、它是对Linux原生unionfs的重写和改进;
2、它的作者怨气应该很大,猜想应该是Linus Torvalds(Linux 之父)一直不让 aufs进入Linux内核主干的缘故,所以我们只能在ubuntu和debian这些发行版本上使用。

对于aufs来说,它最关键的目录结构在/var/lib/docker路径下的diff目录:

/var/lib/docker/aufs/diff/<layer_id>

而这个目录的作用,我们不妨通过一个例子来看下:

现在,我启动一个容器,比如:

docker run -d ubuntu:latest sleep 3600

这时候,docker就会从docker hub上或者你指定的镜像仓库进行pull镜像到本地的系统上。

这个所谓的“镜像”,实际上就是一个Linux操作系统的rootfs,它的内容是Linux操作系统的所有文件和目录,不过,与之前讲述的rootfs稍有不同的是docker镜像使用的rootfs,往往由多个“层”组成:

# docker image inspect ubuntu:latest
...
     "RootFS": {
      "Type": "layers",
      "Layers": [
        "sha256:f49017d4d5ce9c0f544c...",
        "sha256:8f2b771487e9d6354080...",
        "sha256:ccd4d61916aaa2159429...",
        "sha256:c01d74f99de40e097c73...",
        "sha256:268a067217b5fe78e000..."
      ]
    }

不出意外的,这个目录里面正式一个完整的ubuntu操作系统

# ls /var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fcfa2a2f5c89dc21ee30e166be823ceaeba15dce645b3e
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

镜像分为5个层挂载到一个完成的ubuntu文件系统

这个信息记录在aufs的系统目录/sys/fs/aufs下面。

首先,通过查看aufs的挂载信息,我们可以找到这个目录对应的aufs的内部ID(也叫si):

# cat /proc/mounts| grep aufs
none /var/lib/docker/aufs/mnt/6e3be5d2ecccae7cc0fc... aufs rw,relatime,si=972c6d361e6b32ba,dio,dirperm1 0 0

即,si=972c6d361e6b32ba

然后使用这个ID,你就可以在/sys/fs/aufs下查看被联合挂载在一起的各个层的信息:

cat /sys/fs/aufs/si_972c6d361e6b32ba/br[0-9]*
/var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...=rw
/var/lib/docker/aufs/diff/6e3be5d2ecccae7cc...-init=ro+wh
/var/lib/docker/aufs/diff/32e8e20064858c0f2...=ro+wh
/var/lib/docker/aufs/diff/2b8858809bce62e62...=ro+wh
/var/lib/docker/aufs/diff/20707dce8efc0d267...=ro+wh
/var/lib/docker/aufs/diff/72b0744e06247c7d0...=ro+wh
/var/lib/docker/aufs/diff/a524a729adadedb90...=ro+wh

从这些信息里,我们可以看到,镜像的层都放置在/var/lib/docker/aufs/diff目录下,然后被联合挂载在/var/lib/docker/aufs/mnt里面。

而且,从下面的结构可以看出,这个容器的rootfs由三部分组成:

docker-镜像.png

第一部分,只读层。

它是这个容器的rootfs最下面的5层,对应的正式ubuntu:latest镜像的5层,可以看到,它们的挂载方式都是只读的(ro+wh,即readonly+whiteout)

这时,我们可以分别查看一下这些层的内容:

ls /var/lib/docker/aufs/diff/72b0744e06247c7d0...
etc sbin usr var
$ ls /var/lib/docker/aufs/diff/32e8e20064858c0f2...
run
$ ls /var/lib/docker/aufs/diff/a524a729adadedb900...
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

可以看到,这些层,都以增量的方式分别包含了ubuntu操作系统的一部分。

第二部分,可读写层。

它是这个容器的rootfs最上面的一层(6e3be5d2ecccae7cc),它的挂载方式为:rw,可读写,在没有卸任文件之前,这个目录是空的,而一旦在容器里做了写操作,修改产生的内容就会以增量的方式出现在这个层中。

可是,有没有想过一个问题,如果现在删除只读里的一个文件?

为了实现这样的操作,aufs会在可读写层新建一个whiteout文件,把只读层里的文件“遮挡”起来。

比如,你要删除只读层里一个叫test的文件,那么这个删除操作时机上是在可读写层创建一个名叫.wh.test的文件,这样当两个层被联合挂载之后,test文件就会被.wh.test文件“遮挡”起来,“消失”了,这个功能就是“ro+wh”的挂载方式,即只读 +whiteout 的含义。我喜欢把 whiteout 形象地翻译为:“白障”。

所以,最上面这个可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量 rootfs 的好处。

第三部分,init层

它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init 层是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。

需要这样一层的原因是,这些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。

可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。

所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。

最终,这 7 个层都被联合挂载到 /var/lib/docker/aufs/mnt 目录下,表现为一个完整的 Ubuntu 操作系统供容器使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容