什么叫"制作一个镜像"?
Aufs 在Docker中的玩法
上一节好像扯的有点远, 本来是想研究一下Docker是怎么管理这些层级, 以及这些层级分别是干啥的, 结果给扯到镜像ID上去了, 现在必须严肃起来了:
Copy # 用busybox起一个容器
$ docker run -it busybox:latest sh
# 在容器内生成一个 1M 大小的文件
$ dd if=/dev/zero of=test bs=1M count=1
# 随便从容器里删掉一个文件
$ rm bin/find
# 然后用commit的方式生成镜像
$ docker commit a09 xiaohan-building:v2
我们在原有镜像的基础上做出了两个改动, 一个创建操作, 一个删除操作, 来看看按照 aufs 的玩法会发生什么呢? 我们先进入 docker 用来存储镜像的文件夹 /var/lib/docker
Copy # 多出来的 4cd 这个文件夹, 代表我们新产生的层
$ cd /var/lib/docker && ls
ef4da5b601859191dabb3343818295bfaa2112ad # busybox 自带层
4cd218cc42c9b4368543b1dfcd47488145259b1d # 我们Commit所产生的层
$ cd 4cd218cc && ls
test bin root
$ ls -al bin
.wh.find
$ ls -al root
.ash_history
现在一切都真相大白了, 已经完全跟 aufs 一节里提到的知识对接上了, 我们在容器里一共执行了两个动作:
[创建] 创建出来的 /test
文件, 被原模原样带到镜像里, 等待下次联合挂载的时候带到容器里
[删除] 删除的文件会以.wh
文件的形式存在, 代表被删除了
如何组装出一个完整的镜像
我们在上一节里提到了, 一个ID唯一的决定一个镜像, 而一个ID是由镜像的配置文件所决定的. 换句话说, 一个完整的, 包含好几层的镜像, 是通过这个json文件组装出来的. 先把镜像整体搞出来, 看看完整的镜像包含那些内容
Copy $ docker save -o xiaohan-building.tar xiaohan-building:v2 && \
tar -xvf xiaohan-building.tar && \
ls
# [身份证] 告诉你这个镜像叫什么名字, 是什么ID
repositories
# [配置清单] 告诉你如何组装
manifest.json
# 运行变量, 环境变量/ 等参数
dceb31305909be6852b30109eb006f.json
# 底层镜像
cc42b70ac29c27cb9c528153178d46
# 顶层镜像
ff12c2f47a046f2bdd61e7b542fb54
$ cat manifest.json | jq -M
{
"Config": "dceb31305909be6852b30109eb006f.json",
"RepoTags": ["xiaohan-building:v2"],
"Layers": [
# 使用路径下的cc/layer.tar 作为镜像的第一层
"cc42b70ac29c27cb9c528153178d46/layer.tar",
# 使用路径下的ff/layer.tar 作为镜像的第顶层
"ff12c2f47a046f2bdd61e7b542fb54/layer.tar"
]
}
]
$ cat dce.json
{
...
"config": {
...
"OpenStdin": true,
"StdinOnce": true,
# 说明了当时我们是从命令行出发制作出这个镜像的
"Tty": true,
# 环境变量
"Env": ["PATH=/usr/local/sbin:/usr/local/bin"],
# 类似Dockerfile里的 Entrypoint
"Cmd": ["sh"]
},
...
}
如何在Overlay2下组装出一个镜像
其实现在Ubuntu的默认选择已经切换成 Overlay2, 原因我们会在下一节介绍overlay2的时候再说, 简单来说是出于效率考虑, 我们先看看overlay2是怎么玩的, 本质上这两者的基本原理都离不开 union mounting , 先把你的容器存储驱动切换成 overlay2 并重启
Copy # 拉一个包含三层的ubuntu
$ docker pull ubuntu:latest
# 存了三个镜像层, 一个l目录, 什么名字只有一个字母
$ cd /var/lib/docker/overlay2 && ls
5120783b613078666e93b04
e80337d2b3f9b8f513aa493
56db4ed53b76a40926bda33
l
# 记录了三个软连接, 分别指向ubuntu三层镜像
$ ls -al l
IQONIIKCSDRBAJNBDCSBTAZHQB -> ../5120783b613078666e93b04/diff
TBVVT2OB2EINS3RZOLAQ6RSNBG -> ../56db4ed53b76a40926bda33/diff
TEZXOCGIWOSOD3Q4TQN74DNOF6 -> ../e80337d2b3f9b8f513aa493/diff
# 看看这个镜像顶层, 是这三者中的哪一个
$ docker inspect ubuntu:latest
...
"GraphDriver": {
"Data": {
"UpperDir":
# 哟西, ubuntu镜像的顶层是 56db
"/var/lib/docker/overlay2/56db4ed53b76a40926bda33/diff",
"LowerDir":
# ubuntu的次顶层是e8033
"/var/lib/docker/overlay2/e80337d2b3f9b8f513aa493/diff:
# ubuntu的最底层(base)是512
"/var/lib/docker/overlay2/5120783b613078666e93b04/diff",
},
"Name": "overlay2"
}
...
# 切进去看看顶层镜像
$ cd /var/lib/docker/overlay2/56db4ed53b76a40926bda33 && tree
.
|-- diff
| `-- run
|-- link
|-- lower
`-- work
# 顶层镜像的短ID
$ cat link
TBVVT2OB2EINS3RZOLAQ6RSNBGroot
# 顶层镜像下辖两个镜像的短ID, 见上面的l目录, 这两个位置指向两个底层镜像的目录
$ cat lower
l/TEZXOCGIWOSOD3Q4TQN74DNOF6
l/IQONIIKCSDRBAJNBDCSBTAZHQB