如何将docker图像链接到磁盘上的组成层?

从Docker v1.10开始,随着内容可寻址存储的推出,Docker彻底改变了磁盘上图像数据的处理方式。 我明白,现在图层和图像是分开的。 图层仅仅成为文件和目录的集合,没有图像的概念,可以在图像之间自由共享。 看更新和一个更好的解释博客 。

docker pushdocker pull ,通过标准输出(stdout)可以看到图层被传输,尽pipe生成的SHA哈希在目标上完全重新生成。

使用来自ubuntu:14.04的本地构build映像,当使用docker history命令时,可以看到在构build过程中使用的一系列中间映像以及它们贡献的磁盘空间使用情况。

 root@ruifeng-VirtualBox:/var/lib/docker/aufs/diff# docker history image_size IMAGE CREATED CREATED BY SIZE COMMENT 9ae1f372d83c 11 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin/ 0 B aaf66e9fa85b 11 weeks ago /bin/sh -c chown -R martian /home/martian 6.299 MB 9568768134c1 11 weeks ago /bin/sh -c rm -rf /home/martian/potatoes 0 B 2f40f3f58306 11 weeks ago /bin/sh -c mv /home/martian/water_tanks /home 6.289 MB 062e2702ffa2 11 weeks ago /bin/sh -c mv /home/martian/potatoes /home/ma 5.394 kB 7b2d8b4c1dd0 11 weeks ago /bin/sh -c chown -R martian /home/martian 6.299 MB 8fd47fed98d6 11 weeks ago /bin/sh -c #(nop) COPY dir:421da6c71a1f252881 6.289 MB ... 

我可以使用docker inspect命令来获取底层图层。

 root@ruifeng-VirtualBox:/var/lib/docker/aufs/diff# docker inspect image_size | jq -r '.[].RootFS' { "Layers": [ "sha256:a85f35566a268e6f4411c5157ffcffe4f5918b068b04d79fdd80003901ca39da", "sha256:eaaf7298332642da0f8190fa4b96ad46c04b9c1d1682bc3a35d77bded2b1e0a9", "sha256:33a212e8aa5642d3a2ddead146e85912407fc5bbb2a896dab11fcf329177a999", "sha256:f1f25d8c6e56dc4891df147a77f57e756873b57f33ce95e6a0acbe47117c0c8a", "sha256:67852b7d2cf5f0885293fa9df91ebfd8ef0c42ba11a5155f94806f3a96c5e916", "sha256:480d48b7e2864a44c1b2fca0c7e32fbab505f7526ccb25bbfed191c04a9bb7b0", "sha256:18d270fe64aa423e0ffdf24faf0103432027da3d5c12f4505e7daedad9fe2195", "sha256:a73c3f5eb83790bc6d03381a43a20aef7d0d9d97de0cff4b040e8e4c01a3aee5", "sha256:e8d1b67ace73cb92cc00725354e84024153bedae4280149c03fcb52f34d83757", "sha256:19a4b80afc677825fec94adf8b6a45a866f42a38675f87f86e50171ff5e0a280", "sha256:77d412270fbdd9baba1fe73028b786c3a1709feefa9b03be74b8e9f9ce148635", "sha256:2ad21e37389addd577161c981d0c69ab60aa47945172f41f9ec71ada1c1dd4ee", "sha256:771d1e47ca8d8dcf55069786e4c499894fba86f704c808413df00f4f980564e1", "sha256:f9c02c6fa436213c0f220d49c4ee1b913372081010d4506757ec75d3e788847c" ], "Type": "layers" } 

我的问题是,如何将这些标记有SHA哈希的图层链接到上一个命令输出的IMAGE列中列出的图像? 有没有办法find磁盘上这些层的实际位置和大小?

如果我没有错,如果存储驱动程序select是aufs ,那么图层应该保存在/var/lib/docker/aufs/diff 。 但是该文件夹中的内容是用随机生成的ID命名的,这些ID与字面上的任何图层都不匹配。 看来这个匹配只是在Docker引擎中才出于安全考虑。

看来这个匹配只是在Docker引擎中才出于安全考虑。

那么,显然它必须存储在磁盘上的某个地方 ,因为信息需要持久。 我正在使用overlay2驱动程序而不是aufs ,但我猜测布局是相当类似的。 让我们从我在本地的图像开始:

 # docker images | grep alpine alpine latest baa5d63471ea 5 months ago 4.8 MB 

其中有以下几层:

 # docker inspect alpine | jq '.[0].RootFS' { "Type": "layers", "Layers": [ "sha256:011b303988d241a4ae28a6b82b0d8262751ef02910f0ae2265cb637504b72e36" ] } 

让我们看一下/var/lib/docker中与图像ID前缀匹配的东西:

 # cd /var/lib/docker # find . -name 'baa5d63471ea*' -print ./image/overlay2/imagedb/content/sha256/baa5d63471ead618ff91ddfacf1e2c81bf0612bfeb1daf00eb0843a41fbfade3 

这是一个包含一堆数据的JSON文件,包括看起来相关的东西:

  "rootfs": { "type": "layers", "diff_ids": [ "sha256:011b303988d241a4ae28a6b82b0d8262751ef02910f0ae2265cb637504b72e36" ] } 

大! 使用这些信息,我们应该能够获取图层 ID并find所有使用它的图像。 例如,我有一个本地构build的图像,如下所示:

 # docker inspect larsks/qgroundcontrol | jq '.[0].RootFS' { "Type": "layers", "Layers": [ "sha256:c854e44a1a5a22c9344c90f68ef6e07fd479e8ce1030fe141e3236887f1a4920", "sha256:8ba4b4ea187c5ea58c11ee99bbc159b88b303c290b18c2220c9b477f4427bb9e", "sha256:46c98490f5756634de1b1b9ed02a9fae2732984049f4f8fa182959fea924a45c", "sha256:1633f88f8c9fa73c5c0c24f314e81b10dda6c310d41fb87eba02421e1652f6dc", "sha256:0e20f4f8a593705219d1b3c5b1d2f7b8664eb04d706e99add87adbdcceea4a9f", "sha256:cb16829cadf4f4320799bdf23f7400816f1552a011f3e30c2c929382896c3f6f", "sha256:5e6951567308b8aacd8f6bded126ab33a72e7aa584d012a8d0d6283c29d32995", "sha256:66a1378b08992e4043cf4e391d5b7f52f0d8c4b825dc62a2d87c23ba6ea1dd35", "sha256:d397a7c12cc95021d41059a44c137000dfcbf12e6ba295ccb647c075e368e39c", "sha256:8a2c46060eadf56c93467f9445cc49a715a935b0e3b4b439ae8c00fcf3a2157b", "sha256:70a195ccb5fc7423cc15dd55fb446a19bfd2e1d1a4e5132b79f9433b7d7df750", "sha256:349fbf13a3797683fe9a2c8355df2a272da391efab8e11c9e083e3c95c094859" ] } 

让我们find包含相同基本层的其他图像的列表( sha256:c854e44a1a5a22c9344c90f68ef6e07fd479e8ce1030fe141e3236887f1a4920 ):

 # cd /var/lib/docker # grep -rl sha256:c854e44a1a5a22c9344c90f68ef6e07fd479e8ce1030fe141e3236887f1a4920 image/overlay2/imagedb/ 

这将返回像这样的东西:

 image/overlay2/imagedb/content/sha256/d404c11f391c3588ad665fa9ad3f779eb56efc1abbed3cf309b834c824d3c93f image/overlay2/imagedb/content/sha256/dc3313d83519292279466fb5ee7913350d49b8d82f85d537b713ca83d75049e7 image/overlay2/imagedb/content/sha256/dda2981c2844dd1c4a5e004d8bc14633b445f61d23312abba8468251389ed0bc image/overlay2/imagedb/content/sha256/e865d00f6e1e56e7efcfcaf111c52064fc732e68de3eace195492ebf66c7bc74 image/overlay2/imagedb/content/sha256/ea697b65eff199541ec38bbf6ee28085463f0679c9aec3867834f0c14d29d6f4 

这是包含相同图层的图像ID列表。 如果我想将这些id映射回名称,我需要查阅将名称映射到图层的image/overlay2/repositories.json ,或者我需要parsingimage/overlay2/repositories.json的输出。 也许是这样的:

 grep -rl sha256:c854e44a1a5a22c9344c90f68ef6e07fd479e8ce1030fe141e3236887f1a4920 image/overlay2/imagedb/ | while read path; do id=${path##*/} docker images --no-trunc | grep $id | awk '{print $1, $3}' done 

我的系统上将输出:

 larsks/mavproxy sha256:0af8d29ecea9dc870ba0a7740d9f23a55aad8d9edacf4f89f6d6b239b58c7829 larsks/apmplanner sha256:5e715eb065698db5444af5ff341d30007d0b67507885f8aab89701ec2c4731fe larsks/qgroundcontrol sha256:2a6265c23c52d1842ac38ea78fde670910dd40d15a8f0f62f60646ad9b209542 sitl sha256:7420866bd587f7b76fbd23b1c15d0a2b9ca5a04fd2d6e442c62a6b25a195b378 cmd/mavproxy sha256:d00e9707a3d8b1cae319ec88b4ccb26f111bb979ec1978cd32147274ab1704e4 cmd/apmplanner sha256:d17cae44602ad335f518276dfcc8a27a251b619f3f9037c55c278eb49d83d74b cmd/qgroundcontrol sha256:d404c11f391c3588ad665fa9ad3f779eb56efc1abbed3cf309b834c824d3c93f mavproxy sha256:dda2981c2844dd1c4a5e004d8bc14633b445f61d23312abba8468251389ed0bc ubuntu sha256:f753707788c5c100f194ce0a73058faae1a457774efcda6c1469544a114f8644 

…这似乎是合理的。

根据答案中的谜语给出的灵感,我设法find了图层的位置。

例如,假设我们想要findCOPY步骤所贡献的图层的位置,对应于一个id为8fd47fed98d6的中间图像,我们可以先检查它。

 root@ruifeng-VirtualBox:/var/lib/docker# docker inspect 8fd47fed98d6 | jq -r '.[].RootFS' { "Layers": [ "sha256:a85f35566a268e6f4411c5157ffcffe4f5918b068b04d79fdd80003901ca39da", "sha256:eaaf7298332642da0f8190fa4b96ad46c04b9c1d1682bc3a35d77bded2b1e0a9", "sha256:33a212e8aa5642d3a2ddead146e85912407fc5bbb2a896dab11fcf329177a999", "sha256:f1f25d8c6e56dc4891df147a77f57e756873b57f33ce95e6a0acbe47117c0c8a", "sha256:67852b7d2cf5f0885293fa9df91ebfd8ef0c42ba11a5155f94806f3a96c5e916", "sha256:480d48b7e2864a44c1b2fca0c7e32fbab505f7526ccb25bbfed191c04a9bb7b0", "sha256:18d270fe64aa423e0ffdf24faf0103432027da3d5c12f4505e7daedad9fe2195", "sha256:a73c3f5eb83790bc6d03381a43a20aef7d0d9d97de0cff4b040e8e4c01a3aee5", "sha256:e8d1b67ace73cb92cc00725354e84024153bedae4280149c03fcb52f34d83757", "sha256:19a4b80afc677825fec94adf8b6a45a866f42a38675f87f86e50171ff5e0a280" ], "Type": "layers" } 

现在我们试图寻找最后一层。

 root@ruifeng-VirtualBox:/var/lib/docker# find . -name '*19a4b80afc677825fec94adf8b6a45a866f42a38675f87f86e50171ff5e0a280*' root@ruifeng-VirtualBox:/var/lib/docker# 

但是磁盘上没有任何东西。 也许有一些参考文献在那里。 我们可以检查layerdb中的文件内容。

 root@ruifeng-VirtualBox:/var/lib/docker# grep -rl 19a4b80afc677825fec94adf8b6a45a866f42a38675f87f86e50171ff5e0a280 image/aufs/layerdb/ image/aufs/layerdb/sha256/f1824ce70e6d1e8f140b9ba637b7447c00d8158d3bbc1f72b491766ab54dd449/diff 

我们可以看到,这一层实际上是f1824ce70e6d1e8f140b9ba637b7447c00d8158d3bbc1f72b491766ab54dd449diff 。 让我们find它。

 root@ruifeng-VirtualBox:/var/lib/docker# find . -name '*f1824ce70e6d1e8f140b9ba637b7447c00d8158d3bbc1f72b491766ab54dd449*' ./image/aufs/layerdb/sha256/f1824ce70e6d1e8f140b9ba637b7447c00d8158d3bbc1f72b491766ab54dd449 

并findcache-id ,将我们引导到aufs/diff文件夹中的实际位置。

 root@ruifeng-VirtualBox:/var/lib/docker# cat image/aufs/layerdb/sha256/f1824ce70e6d1e8f140b9ba637b7447c00d8158d3bbc1f72b491766ab54dd449/cache-id c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637 

让我们进入位置并检查。

 root@ruifeng-VirtualBox:/var/lib/docker# cd aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637 root@ruifeng-VirtualBox:/var/lib/docker/aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637# find . . ./home ./home/martian ./home/martian/water_tanks ./home/martian/water_tanks/IMG_0052.JPG root@ruifeng-VirtualBox:/var/lib/docker/aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637# 

它包含所有通过COPY步骤被复制到图像中的文件和目录。 也可以检查图层的大小。

 root@ruifeng-VirtualBox:/var/lib/docker# du -sh aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637 6.1M aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637 

这将为Docker所使用的Union File System和Copy-on-Write机制提供一些深入的了解,如果后续的层也以相同的方式进行检查的话。

这也可以以相反的顺序完成。 我们可以查找一个文件或目录,这个文件或目录应该位于图像内部,应该放在aufs/diff里面,然后使用cache-id追溯到图层。

 root@ruifeng-VirtualBox:/var/lib/docker# find . -name '*water_tanks*' ./aufs/diff/c097799b7946231fb60511b442c10cd0b56ee17a12b376149f305adda67e7637/home/martian/water_tanks