Docker的graph driver主要用于管理和维护镜像,包括把镜像从仓库下载下来,到运行时把镜像挂载起来可以被容器访问等,都是graph driver做的。涉及的docker命令有

-         Docker pull

-         Docker push

-         Docker import

-         Docker export

-         Docker load

-         Docker save

-         Docker build


Docker的graph driver做的事情,基本上是对docker的image定义的实现,而OCI的image-spec是基于docker的image spec的,所以理论dockergraph driver做的事情,都应该被image-spec的实现所覆盖。


目前docker支持的graph driver有:

-         Overlay

-         Aufs

-         Devicemapper

-         Btrfs

-         Zfs

-         Vfs

这些driver各有优劣,以后会慢慢补充对比。


Overlay driver介绍

Graph driver中最复杂的部门就是梳理清楚在构建各种镜像层关系时涉及的各种id以及他们的组织关系。特别是docker镜像在支持content addressable之后,镜像的id组织关系变得异常复杂。Overlay driver中,对镜像的id会涉及到多种类型:

-         对一个镜像生成的唯一id值,下文称为image-id

-         运行容器时把镜像挂载起来后生成的一个唯一id值,下文称为mount-id   #docke ps查看到的id

-         对每一个镜像层生成的一个唯一的随机id,下文中称为cache-id

-         根据每一个镜像层的内容单独生成的content addressable id,下文称为layer-id

-         根据每一层镜像,以及该镜像的所有底层镜像的内容生成的content addressable id,下文称为chain-id

对于一个镜像来说,其最底层的layer,其layer-id和chain-id是一样的。


Layer-id和chain-id的存在比较好理解,其中chain-id的概念也是image-spec中定义必须有的,cache-id的存在感觉必要性不大,目前不清楚为什么还要搞一个cache-id,猜测可能是为了向前兼容的原因。Image-id,mount-id和cache-id都是随机生成的,可以合起来跟content addressable id对比理解。


关键目录介绍

/var/lib/docker/overlay

这里存放的是镜像的每一层layer解压后的结果,以及基于每一个镜像生成容器后,对镜像合并挂载后的目录和对应的init目录。这里的id就是cache-id和mount-id.

对于容器的挂载目录,比如对某个容器docker inspect后查询到的“GraphDriver”中的挂载目录,里面又分几个子目录:

-         /var/lib/docker/overlay/<id>/merged      这是所有镜像层合并后的结果,就是容器中进程看到的结果

-         /var/lib/docker/overlay/<id>/upper         这是上面的只读层

-         /var/lib/docker/overlay/<id>/work          这是overlay生成用来做cow相关操作的

-         /var/lib/docker/overlay/<id>/lower-id    这里存放了镜像层中最上层的cache-id


/var/lib/docker/image/overlay/imaged/content/sha256

这里存放的是每一个镜像的配置信息,其id都是image-id,里面是json格式,其内容跟docker inspect查看镜像的信息是一样的,这里面会涉及到一些id:

[root@localhostimagedb]# docker inspectc5f1cf30c96b5b55c0e6385f2ecb791790eacfdc874500ec3dd865789e358dd1

[

    {

        "Id":"sha256:c5f1cf30c96b5b55c0e6385f2ecb791790eacfdc874500ec3dd865789e358dd1",

        …

        "Container":"47dc052ce6dc564733ec57eb0133693731d20383f1db037c578f6330a78ca643",

        "ContainerConfig": {

            …

            "Image":"cdc870605343a807ec3bb9da56f84249c846b5ba7dba18bb226a4af9f5e1451a",

            …

        },

        …

        "Config": {

            …

            "Image":"cdc870605343a807ec3bb9da56f84249c846b5ba7dba18bb226a4af9f5e1451a",

            …

        },

        …

        "GraphDriver": {

            "Name":"overlay",

            "Data": {

                "RootDir":"/var/lib/docker/overlay/9aaabd8f23f938937269563a119307e4f8859e8cabc274c63568e3e473cd2d0b/root"

            }

        },

        "RootFS": {

            "Type":"layers",

            "Layers": [

               "sha256:7aae4540b42d10456f8fdc316317b7e0cf3194ba743d69f82e1e8b10198be63c",

               "sha256:3ce512daaf78307e3a2c5adef7741d9ce9d61449a9a642cafd9f474a50e8c5d0",

               "sha256:7f18b442972bf737eadfff445088375d38f0f455f25ea94277b70050de3ae4b1",

               "sha256:a3b5c80a4ebaf7a0a1b92219b3dfb7109a14b38bebd6b55870a3aec90743a263",

               "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"

            ]

        }

    }

]


对以上id的解释:

-         Id:镜像的image-id

-         Container:创建该镜像的容器id

-         ContainerConfig.Image:创建该镜像的容器基于的镜像的image-id

-         Config.Image:同ContainerConfig.Image

-         GraphDriver.Data.RootDir:路径中的id为该镜像最上面的layer的cache-id

-         RootFS.Layers:该镜像的所有层的id,这里的id是layer-id


/var/lib/docker/image/overlay/layerdb/mounts

这里记录的是当前存在的容器的id,里面的文件:

-         mount-id:就是容器运行起来后的挂载mount-id

-         init-id:跟mount-id一样,只是后面加了-init,这个层的存在是为了解决一些容器的其他目录的挂载问题,具体原因待分析

-         parent:这里存放的就是容器使用的镜像层的最上层layer的id,是一个chain-id,跟/var/lib/docker/overlay/<mount-id>/lower-id里指的是同一个,但lower-id里的是cache-id。

/var/lib/docker/image/overlay/layerdb/sha256

该目录下存放的就是容器镜像的每一层的源数据了,这里的id都是chain-id,每个文件夹下面就是该镜像层中的一些信息:

-         Cache-id:对应的是/var/lib/docker/overlay目录下的cache-id

-         Diff:对应是这个chain中,最上层的layer的id,也就是为这个chain附加上去的层,是一个layer-id

-         Parent:就是这个chain除去最上层的layer后,上一个chain的chain-id

-         Size:是这个chain附加上去的层的大小

-         Tar-split.json.gz:是对这个chain附加上去的layer的源数据解压后重新通过tar-split的方式压缩后的数据包,对于为什么需要tar-split重新压缩,原因可以参考image-spec中的描述。