# docker文件结构 ## Image file system ### image 存储结构 #### repository元数据 repository 相当于是本地镜像的一个存储库(包含了镜像的所有迭代版本)。repository元数据位于`/var/lib/docker/image/overlay2/repositories.json`,overlay2为使用的联合文件类型 ``` 当前机器上没有镜像 [root@mydocker ~]# cat /var/lib/docker/image/overlay2/repositories.json | jq { "Repositories": {} } ``` > 下载一个镜像,观察此文件变化 ``` [root@mydocker ~]# docker pull dokken/centos-7 [root@mydocker ~]# docker pull dokken/centos-7 Using default tag: latest latest: Pulling from dokken/centos-7 2d473b07cdd5: Pull complete 16767af39bf6: Pull complete Digest: sha256:5bcc937f459bd68c9c532edecc63f4834ba60565953d44b3ca42e9f73a9bc1f5 Status: Downloaded newer image for dokken/centos-7:latest docker.io/dokken/centos-7:latest 其中Digest: sha256:5bcc937f459bd68c9c532edecc63f4834ba60565953d44b3ca42e9f73a9bc1f5 称为镜像的摘要,在拉取镜像的时候可以看到它。也可以直接使用docker pull dokken/centos-7@sha256:5bcc937f459bd68c9c532edecc63f4834ba60565953d44b3ca42e9f73a9bc1f5的方式来拉取镜像 [root@mydocker ~]# cat /var/lib/docker/image/overlay2/repositories.json | jq { "Repositories": { "dokken/centos-7": { "dokken/centos-7:latest": "sha256:b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1", "dokken/centos-7@sha256:5bcc937f459bd68c9c532edecc63f4834ba60565953d44b3ca42e9f73a9bc1f5": "sha256:b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1" } } } 其中sha256:b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1,这个为docker images 中IMAGE ID的完整ID [root@mydocker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE dokken/centos-7 latest b5e4c617efde 3 weeks ago 300MB ``` #### image元数据 image元数据包括了镜像架构(如 amd64)、操作系统(如 linux)、镜像默认配置、构建该镜像的容器 ID 和配置、创建时间、创建该镜像的 docker 版本、构建镜像的历史信息以及 rootfs 组成。其中构建镜像的历史信息和 rootfs 组成部分除了具有描述镜像的作用外,还将镜像和构成该镜像的镜像层关联了起来。Docker 会根据历史信息和 rootfs 中的 **diff_ids** 计算出构成该镜像的镜像层的存储索引 **chainID**,这也是 docker 镜像存储中基于内容寻址的核心技术。 **images元数据**被保存在文件**/var/lib/docker/image//imagedb/content/sha256/**中。 ``` [root@mydocker ~]# cat /var/lib/docker/image/overlay2/imagedb/content/sha256/b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1 | jq { "architecture": "amd64", "config": { "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/usr/lib/systemd/systemd" ], "Labels": { "maintainer": "sean@sean.io", "org.label-schema.build-date": "2021-08-22T00:12:05Z", "org.label-schema.description": "A Docker container for testing centos-7", "org.label-schema.license": "GPLv2", "org.label-schema.name": "test-kitechen/dokken-images", "org.label-schema.schema-version": "1.0", "org.label-schema.vcs-ref": "3d8e5194", "org.label-schema.vcs-url": "https://github.com/test-kitechen/dokken-images", "org.label-schema.vendor": "test-kitchen", "org.opencontainers.image.created": "2020-11-13 00:00:00+00:00", "org.opencontainers.image.licenses": "GPL-2.0-only", "org.opencontainers.image.title": "CentOS Base Image", "org.opencontainers.image.vendor": "CentOS" }, "ArgsEscaped": true, "OnBuild": null }, "created": "2021-08-22T00:12:53.331988821Z", "history": [ { "created": "2020-11-14T00:20:04.1030585Z", "created_by": "/bin/sh -c #(nop) ADD file:b3ebbe8bd304723d43b7b44a6d990cd657b63d93d6a2a9293983a30bfc1dfa53 in / " }, { "created": "2020-11-14T00:20:04.452344367Z", "created_by": "/bin/sh -c #(nop) LABEL org.label-schema.schema-version=1.0 org.label-schema.name=CentOS Base Image org.label-schema.vendor=CentOS org.label-schema.license=GPLv2 org.label-schema.build-date=20201113 org.opencontainers.image.title=CentOS Base Image org.opencontainers.image.vendor=CentOS org.opencontainers.image.licenses=GPL-2.0-only org.opencontainers.image.created=2020-11-13 00:00:00+00:00", "empty_layer": true }, { "created": "2020-11-14T00:20:04.644613188Z", "created_by": "/bin/sh -c #(nop) CMD [\"/bin/bash\"]", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL maintainer=sean@sean.io", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "ARG BUILD_DATE", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "ARG VCS_REF", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.schema-version=1.0", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.build-date=2021-08-22T00:12:05Z", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.name=test-kitechen/dokken-images", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.description=A Docker container for testing centos-7", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.vcs-url=https://github.com/test-kitechen/dokken-images", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.vcs-ref=3d8e5194", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "LABEL org.label-schema.vendor=test-kitchen", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "RUN |2 BUILD_DATE=2021-08-22T00:12:05Z VCS_REF=3d8e5194 /bin/sh -c yum -y install binutils ca-certificates cronie curl dmidecode e2fsprogs ethtool file gnupg2 hostname initscripts iproute iptables iputils less lsof nc net-tools nmap openssl passwd procps strace sudo system-lsb-core systemd-sysv tcpdump telnet util-linux vim-minimal wget which && yum clean all && rm -rf /var/cache/yum && rm -rf /var/log/* && find /etc/systemd/system /lib/systemd/system -path '*.wants/*' \\( -name '*getty*' -or -name '*systemd-logind*' -or -name '*systemd-vconsole-setup*' -or -name '*systemd-readahead*' -or -name '*udev*' \\) -exec rm -v \\{} \\; && systemctl set-default multi-user.target && systemctl mask dev-hugepages.mount sys-fs-fuse-connections.mount network.service # buildkit", "comment": "buildkit.dockerfile.v0" }, { "created": "2021-08-22T00:12:53.331988821Z", "created_by": "CMD [\"/usr/lib/systemd/systemd\"]", "comment": "buildkit.dockerfile.v0", "empty_layer": true } ], "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02", "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2" ] } } ``` 这里有几个概念: - **ImageID:**唯一标志一个镜像,其数值根据该镜像的元数据配置文件采用sha256算法的计算获得。 ``` 例如: [root@mydocker ~]# sha256sum /var/lib/docker/image/overlay2/imagedb/content/sha256/b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1 b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1 /var/lib/docker/image/overlay2/imagedb/content/sha256/b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1 输出结果前面为校验值,后面为文件名 ``` - **cacheID:**由宿主机随即生成的一个uuid,根镜像层文件一一对应,用于宿主机标志和索引镜像层文件 - **diffID:**镜像层校验ID、根据该镜像层的打包文件校验获得 - **parent:**父镜像层的chainID(最底层不含该文件) - **chainID:**docker内容寻址机制采用的索引ID,其值根据当前层和所有祖先层的diffID算得: - 若该镜像层是最底层,那么其chainID 和 diffID 相同 - 否则,chainID=sha256(父层chainID+" "+本层diffID) - **layerID** : docker pull的时候远程压缩数据的sha256sum校验值 ##### 查看镜像的详细信息 ``` [root@mydocker ~]# docker image inspect b5e4c617efde6054cddcb [ { "Id": "sha256:b5e4c617efde6054cddcbc4e815fdb9f7f603932811206a076662bfbb29be9a1", "RepoTags": [ "dokken/centos-7:latest" ], "RepoDigests": [ "dokken/centos-7@sha256:5bcc937f459bd68c9c532edecc63f4834ba60565953d44b3ca42e9f73a9bc1f5" ], "Parent": "", "Comment": "buildkit.dockerfile.v0", "Created": "2021-08-22T00:12:53.331988821Z", "Container": "", "ContainerConfig": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": null, "Cmd": null, "Image": "", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": null }, "DockerVersion": "", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/usr/lib/systemd/systemd" ], "ArgsEscaped": true, "Image": "", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "sean@sean.io", "org.label-schema.build-date": "2021-08-22T00:12:05Z", "org.label-schema.description": "A Docker container for testing centos-7", "org.label-schema.license": "GPLv2", "org.label-schema.name": "test-kitechen/dokken-images", "org.label-schema.schema-version": "1.0", "org.label-schema.vcs-ref": "3d8e5194", "org.label-schema.vcs-url": "https://github.com/test-kitechen/dokken-images", "org.label-schema.vendor": "test-kitchen", "org.opencontainers.image.created": "2020-11-13 00:00:00+00:00", "org.opencontainers.image.licenses": "GPL-2.0-only", "org.opencontainers.image.title": "CentOS Base Image", "org.opencontainers.image.vendor": "CentOS" } }, "Architecture": "amd64", "Os": "linux", "Size": 299984025, "VirtualSize": 299984025, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/7e6c6f4d981245e86875c3243dc6a3420dea50fab88a8da4c4d2c495738d2006/diff", "MergedDir": "/var/lib/docker/overlay2/60822582a312e34da1d8659b7e65778e026d10bb26d94bdeacf7ce353f0deec1/merged", "UpperDir": "/var/lib/docker/overlay2/60822582a312e34da1d8659b7e65778e026d10bb26d94bdeacf7ce353f0deec1/diff", "WorkDir": "/var/lib/docker/overlay2/60822582a312e34da1d8659b7e65778e026d10bb26d94bdeacf7ce353f0deec1/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02", "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ] ``` 其中有一个rootfs的键值对,如下 ``` "RootFS": { "Type": "layers", "Layers": [ "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02", "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2" ] }, ``` 这是镜像的底层的rootfs,但是我们发现这些sha256值和第一步拉取下来的层layerID不一致。这是为什么呢? 因为pull下来的是压缩的数据,`layerID`是压缩数据的sha256的值(`Layer ID`指`Distribution`根据`layer compressed data`计算的),而inspect rootfs中的值是解压后,对解压的内容进行sha256的值他们是diffID,是在本地由Docker根据`layer uncompressed data`计算的。 记住这里的`rootfs layers`的值是`diffID`。其排列也是有顺序的,从上到下依次表示镜像层的最低层到最顶层。 ##### 远程拉取下来的layerID和解压后的diffID的关联 ``` [root@mydocker ~]# ls /var/lib/docker/image/overlay2/distribution/ diffid-by-digest v2metadata-by-diffid ``` 其中`diffid-by-digest`保存了`digest(layerID)->diffID`的映射关系,即`distribution hashes`和`Content hashes`的映射关系。也即是正向查询。比如 ``` [root@mydocker ~]# cat /var/lib/docker/image/overlay2/distribution/diffid-by-digest/sha256/16767af39bf67993f807b5c338551fa98f8cebdca4dff3fe8b2d846799d79d89 sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2 //得到了对应的diffID,也就是rootFS里的layers显示的diffID [root@mydocker ~]# cat /var/lib/docker/image/overlay2/distribution/diffid-by-digest/sha256/2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 //得到了对应的diffID ``` `v2metadata-by-diffid`保存了`diffid -> (digest,repository)`的映射关系,这可以方便查找layer的digest以及其所属的repository,也就是反向查询,可以从diffID -> layerID(也就是digest),比如 ``` [root@mydocker ~]# cat /var/lib/docker/image/overlay2/distribution/v2metadata-by-diffid/sha256/174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 [{"Digest":"sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc","SourceRepository":"docker.io/dokken/centos-7","HMAC":""}] //得到相应的layerID和仓库的相关信息 ``` ##### 由diffID计算chainID 从diffID组成chainID: layer.ChainID只用本地,根据layer.DiffID计算,并用于layerdb的目录名称。 chainID唯一标识了一组(像糖葫芦一样的串的底层)diffID的hash值,包含了这一层和它的父层(底层), 当layer只有1层时,也就是`chainID(layer0)==diffID(layer0)`; 当layer有多层时,`ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))` ``` [root@mydocker ~]# cd /var/lib/docker/image/overlay2/layerdb/sha256 #这个目录下保存了所有的chainID, [root@mydocker sha256]# ll total 0 drwx------. 2 root root 71 Sep 17 19:35 174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 drwx------. 2 root root 85 Sep 17 19:35 29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7 [root@mydocker sha256]# docker image inspect b5e4c617efde6054cddcb [ { ... "RootFS": { "Type": "layers", "Layers": [ "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02", "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2" ] }, ... } ] ``` inspect这个2个diffID,第一个是最底层的174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02,所以`diffID(layer0)==chainID(layer0)` ``` [root@mydocker sha256]# ls /var/lib/docker/image/overlay2/layerdb/sha256/174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02/ cache-id diff size tar-split.json.gz [root@mydocker sha256]# cat /var/lib/docker/image/overlay2/layerdb/sha256/174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02/cache-id 7e6c6f4d981245e86875c3243dc6a3420dea50fab88a8da4c4d2c495738d2006 [root@mydocker sha256]# cat /var/lib/docker/image/overlay2/layerdb/sha256/174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02/diff sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 ``` 然后这个文件夹中包含了diff、cache-id等,最主要的是Diff文件保存了这个层的diffID , cache-id为具体`/var/lib/docker/overlay2/`存储路径。 第二个ChanID`29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7`该如何计算呢? ``` [root@mydocker ~]# cd /var/lib/docker/image/overlay2/layerdb/sha256 #这个目录下保存了所有的chainID, [root@mydocker sha256]# ll total 0 drwx------. 2 root root 71 Sep 17 19:35 174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 drwx------. 2 root root 85 Sep 17 19:35 29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7 [root@mydocker sha256]# docker image inspect b5e4c617efde6054cddcb [ { ... "RootFS": { "Type": "layers", "Layers": [ "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02", "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2" ] }, ... } ] [root@mydocker sha256]# echo -n 'sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02 sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2' | sha256sum 29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7 - 一定注意要加上 “sha256:”和中间的空格“ ”这两个字符,否则计算就错误了。 ``` 另外一个ChanID`29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7`的计算方式为 `SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))` ``` [root@mydocker sha256]# ls /var/lib/docker/image/overlay2/layerdb/sha256/29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7/ cache-id diff parent size tar-split.json.gz ``` 这个chainID文件夹中包含了parent文件,这个值为ChainID(layerN-1),diff文件存储了DiffID(layerN),cache-id为具体`/var/lib/docker/overlay2/`存储路径。 ##### cache-id得到最终的磁盘文件 在`/var/lib/docker/overlay2//diff` ``` 最底层的layer [root@mydocker sha256]# ls /var/lib/docker/overlay2/7e6c6f4d981245e86875c3243dc6a3420dea50fab88a8da4c4d2c495738d2006/diff/ anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var 第二次layer [root@mydocker sha256]# ll /var/lib/docker/overlay2/60822582a312e34da1d8659b7e65778e026d10bb26d94bdeacf7ce353f0deec1/diff/ total 4 drwxr-xr-x. 27 root root 4096 Aug 22 08:12 etc drwxr-xr-x. 4 root root 48 Aug 22 08:12 run drwxr-xr-x. 8 root root 81 Nov 13 2020 usr drwxr-xr-x. 7 root root 64 Nov 13 2020 var ``` ### 总结 - Overlay2比overlay更加高效,因为overlay2优化了inode的利用。 - layerID -> diffID -> chainID -> cacheID - layerID和diffID的对应关系在diffid-by-digest和v2metadata-by-diffid - chainID主要存在于/var/lib/docker/image/overlay2/layerdb/sha256/, - cacheID主要存在于/var/lib/docker/overlay2/ ![关联图](https://www.xieys.club/images/posts/docker-images.jpg) ## Container file system 一个容器完整的层应由三个部分组成: 1. 镜像层:也称为rootfs,提供容器启动的文件系统。rootfs也就是我们上一节中分析的image文件。镜像层属于roLayer。 2. init层: 用于修改容器中一些文件如/etc/hostname,/etc/hosts,/etc/resolv.conf等。init层属于mountedLayer。 3. 容器层:使用联合挂载统一给用户提供的可读写目录。容器层属于mountedLayer。 我们启动一个容器来看看init层和容器层都长啥样。先启动一个container ``` [root@mydocker sha256]# docker run -itd --name test dokken/centos-7:latest 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e ``` 到mountedLayer的元数据目录`/var/lib/docker/image//layerdb/mounts//`查看该container的init层与容器层元数据 ``` [root@mydocker mounts]# cd /var/lib/docker/image/overlay2/layerdb/mounts/49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e/ [root@mydocker 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e]# ls init-id mount-id parent [root@mydocker 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e]# cat init-id 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35-init [root@mydocker 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e]# cat mount-id 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35 [root@mydocker 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e]# cat parent sha256:29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7 ``` 可以看到该文件夹有3种文件 - mount-id:存储在`/var/lib/docker/overlay2`的目录名称 - init-id:initID是再mountID后加了一个-init,同时initID就是存储在/var/lib/docker/overlay2/的目录名称。 - parent:容器所基于的**镜像的最上层的chain_id**。(注意这个parent和roLayer元数据的parent的不同之处) > init layer的内容 ``` [root@mydocker 49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e]# cd /var/lib/docker/overlay2/ [root@mydocker overlay2]# tree 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35-init/ 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35-init/ ├── committed ├── diff │   ├── dev │   │   ├── console │   │   ├── pts │   │   └── shm │   └── etc │   ├── hostname │   ├── hosts │   ├── mtab -> /proc/mounts │   └── resolv.conf ├── link ├── lower └── work └── work ``` 可以看到除了一些常规文件以外,diff里面只有一些/etc/hosts、/etc/resolv.conf等配置文件。需要这一层的原因是当容器启动时候,这些本该属于image层的文件或目录,比如hostname,用户需要修改,但是image层又不允许修改,所以启动时候通过单独挂载一层init层,通过修改init层中的文件达到修改这些文件目的。而这些修改往往只读当前容器生效,而在docker commit提交为镜像时候,并不会将init层提交。 > container layer的内容 ``` [root@mydocker overlay2]# ls 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35 diff link lower merged work [root@mydocker overlay2]# ls 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35/diff/ [root@mydocker overlay2]# ls 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35/merged/ anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var ``` 我们可以看到merged目录就是容器内部进程所看到的文件时图,他是由镜像层,init层与容器层联合挂载而来的。 另外可以看到diff文件夹是空的,说明容器还未对文件进行任何修改。如果我们对某文件进行修改的话会怎么样了。比如我们在容器中删除`/etc/bashrc 文件。 ``` [root@mydocker overlay2]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 49cceb46e074 dokken/centos-7:latest "/usr/lib/systemd/sy…" 50 minutes ago Up 50 minutes test [root@mydocker overlay2]# docker exec -it 49 bash [root@49cceb46e074 /]# rm -rf /etc/bashrc 然后再看diff文件夹 [root@mydocker overlay2]# tree 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35/diff/ 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35/diff/ ├── etc │   └── bashrc └── root [root@mydocker overlay2]# ll 2034ad2a28dbf4ae0f7f2390d22196f760f1f635b30cdebe7a513307b7b9ae35/diff/etc/ -l total 0 c---------. 1 root root 0, 0 Sep 17 21:46 bashrc ``` 可以看到diff文件夹下多出来一个`/etc/bashrc`的whiteout文件,此文件覆盖了下层的`/etc/bashrc`,导致我们在container中看不到它了,但它在image中依然存在。 ### 总结 ![container](https://www.xieys.club/images/posts/container.jpg)