准备工作
这句话好像被说过无数次了, 以至于所有人都知道镜像的确是分层的, 在上面一节我们说了多层镜像是如何merge成一个统一的目录结构. 这一节我们再由顶向下看看实际操作中镜像是怎么玩的. 首先我们将Docker的文件系统 (从默认的overlay2) 切换成传统的 aufs 模式:
# 确认一下你的系统是否支持aufs挂载模式
$ grep aufs /proc/filesystems
nodev aufs
# 指定Docker使用aufs模式启动
$ echo '{"storage-driver": "aufs"}' > /etc/docker/daemon.json
# 重启Docker
$ systemctl restart docker
# 检查Docker是不是按照aufs模式挂载
$ docker info | grep aufs
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
# 拉个镜像当示例, 我们选择最简单的busybox
$ docker pull busybox
下面开始整活👇
镜像ID是怎么决定的
提前说一下, 本节会涉及一大堆镜像层ID, 看起来会比较蛋疼
# 拿到镜像ID
$ docker images
REPOSITORY TAG IMAGE ID SIZE
busybox latest f0b02e9d092d 1.23MB
# 检查镜像层级结构
$ docker history busybox:latest
IMAGE CREATED BY SIZE
f0b02e9d092d /bin/sh -c #(nop) CMD ["sh"] 0B
ef4da5b60185 /bin/sh -c #(nop) ADD file:6098… 1.23MB
#
# busybox:latest # f09
# |-- 顶层 # f09 由dockerfile中的 CMD 命令生成
# `-- 底层 # ef4 由dockerfile中的 ADD 命令生成
#
这回搞真的了, 我们看看docker是怎么玩的, 我们可以看到这个镜像分成两层, 其中顶层的ID被拿来当成镜像ID, 换句话说, 如果我们制造一个镜像, 我们就拿它顶层的ID当做镜像ID, 验证一下:
# 因为dockerfile里有"CMD", 因此即使不指定命令, 也按照"sh"运行
$ docker run busybox:latest
# 现在把刚刚跑起来的容器, 以commit的方式制作成镜像
$ docker commit 9c2376480769 xiaohan-building:latest
sha256:f6f28010e18c8853a38cf5889cbeabd5d3a15e42aa0bef1d1b769358780d36f0
# 看看新生成的 xiaohan-building 镜像, 镜像ID为f6f
$ docker images
REPOSITORY TAG IMAGE ID SIZE
xiaohan-building latest f6f28010e18c 1.23MB
# 果然, 顶层ID被拿来当成镜像ID了
$ docker history
IMAGE CREATED BY SIZE
f6f28010e18c sh 0B
f0b02e9d092d /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> /bin/sh -c #(nop) ADD file:609… 1.23MB
那么顶层的ID又是怎么计算出来的呢?
# 通过保存 / 解压的方式拿到镜像的详细数据
$ docker save -o xiaohan-image.tar xiaohan-building:latest
$ tar -xvf xiaohan-image.tar
# 看看出来了
$ cat f6f.json | sha256sum
f6f28010e18c8853a38cf5889cbeabd5d3a15e42aa0bef1d1b769358780d36f0 -
# 这个f6f.json是什么鬼畜
$ cat f6f.json | jq -M
{
"architecture": "amd64",
"config": {
"Hostname": "9c2376480769",
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
}
...
}
懂了, f6f 就是这个镜像的参数, 一个大json, 然后我们把这个json经过sha256计算就能拿到这一层的镜像ID, 因为每个镜像参数是唯一的, 因此sha256 → 镜像层ID一定是唯一的
# 镜像的所有内容现在都会存在这里, 我们进去看看都有啥
$ cd /var/lib/docker/aufs && ls
diff layers mnt
$ ls diff