目录

docker文件结构

Image file system

image 存储结构

repository元数据

repository 相当于是本地镜像的一个存储库(包含了镜像的所有迭代版本)。repository元数据位于/var/lib/docker/image/overlay2/repositories.json,overlay2为使用的联合文件类型

1
2
3
4
5
6
当前机器上没有镜像
[root@mydocker ~]# cat /var/lib/docker/image/overlay2/repositories.json | jq
{
  "Repositories": {}
}

下载一个镜像,观察此文件变化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[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/<graph_driver>/imagedb/content/sha256/<image_id>**中。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
[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算法的计算获得。

    1
    2
    3
    4
    5
    
    例如:
    [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校验值

查看镜像的详细信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
[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的键值对,如下

1
2
3
4
5
6
7
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02",
                "sha256:a318b10552fa3b1a55ce6051c9ebc9bab2ecdff32c839594dc0366c4ecde82b2"
            ]
        },

这是镜像的底层的rootfs,但是我们发现这些sha256值和第一步拉取下来的层layerID不一致。这是为什么呢?

因为pull下来的是压缩的数据,layerID是压缩数据的sha256的值(Layer IDDistribution根据layer compressed data计算的),而inspect rootfs中的值是解压后,对解压的内容进行sha256的值他们是diffID,是在本地由Docker根据layer uncompressed data计算的。 记住这里的rootfs layers的值是diffID。其排列也是有顺序的,从上到下依次表示镜像层的最低层到最顶层。

远程拉取下来的layerID和解压后的diffID的关联
1
2
[root@mydocker ~]# ls /var/lib/docker/image/overlay2/distribution/
diffid-by-digest  v2metadata-by-diffid

其中diffid-by-digest保存了digest(layerID)->diffID的映射关系,即distribution hashesContent hashes的映射关系。也即是正向查询。比如

1
2
3
4
5
[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),比如

1
2
[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))

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[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)

1
2
3
4
5
6
[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/<cache-id>存储路径。

第二个ChanID29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7该如何计算呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[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:”和中间的空格“ ”这两个字符,否则计算就错误了。

另外一个ChanID29fa597bd8cbb6966c2ea3b5c5b4c7eb307f36407c1f82045bfa05505a3e6aa7的计算方式为

SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))

1
2
3
[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>存储路径。

cache-id得到最终的磁盘文件

/var/lib/docker/overlay2/<cache-id>/diff

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
最底层的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

1
2
[root@mydocker sha256]# docker run -itd --name test dokken/centos-7:latest
49cceb46e0742a5d056b6c968bba25fa3ea857e58732c5a33d7c1bd794c96b4e

到mountedLayer的元数据目录/var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/查看该container的init层与容器层元数据

1
2
3
4
5
6
7
8
9
[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的内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[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的内容

1
2
3
4
5
6
[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 文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[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中依然存在。

总结

https://www.xieys.club/images/posts/container.jpg