Docker Daemon是服务端程序,接收到image create请求,开始Docker pull执行流程…
在开始分析程序之前,以我们对Docker的认知判断该流程可能涉及到的模块:
1)R:Router 路由模块
,docker 镜像处理入口
2)I:Image管理模块
,镜像的元数据管理,镜像大小、镜像创建时间、镜像ID、镜像父子关系维护等。
3)L:Layer管理模块
,在第一节中有提到Docker的存储目录设计到各种ID关系,在Layer生成管理,同时Layer管理层负责调用graphDriver 实现联合文件系统的存储与管理。
4)G:GraphDriver管理模块
,实现联合文件系统的存储与管理。
5) D:Distribution管理模块
,负责与远程镜像仓库通信,下载manifest文件、下载Layer镜像等。
6)F: Reference管理模块
,实现对所有镜像的Ref管理。
作为一个懒程序员,为方便后续描述流程,这里对模块进行编码定义R、I、L、G、D、F,除此之外,Daemon包含ImageService,对Image操作执行流程进行处理、调度。
执行流程:
1.R模块接收到外部http请求,其中会携带Form表单,包括repo、tag、auth等信息,如果执行docker pull nginx
,则tag值为latest;如果执行docker pull nginx@sha256:0d17bxxxx
,表示使用Digest匹配镜像,则tag为sha256:0d17bxxxx
。
2.根据Tag内容确定其Ref类型,是NamedTaged 、 Canonical、还是Reference(包含Name、Tag、Digest)。
3.执行D模块的Pull操作,以下操作发生在D模块内:
1)请求RegistryService
模块,获取与该Ref相关的远程仓库信息,以及请求的远端地址列表信息endpoints。RegistryService功能比较简单,与registry-mirrors
、insecure-registries
等配置一起讲(TODO:Q1
)。
2)选择endpoint第一个创建客户端句柄,配置Token参数、metadata参数等。
3)请求远端仓库获取manifest文件,携带Ref参数:tag 或 digest,远端返回manifest文件,具体长这样:
{
"manifests": [{
"digest": "sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 1570
}, {
"digest": "sha256:50ab7908620ee92646ddcd9fe321f969cdff672819fd9c8427448f67f59ef32e",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 1570
}, {
"digest": "sha256:83b62637ee944df8444dd064065c3ee0c39965467bfb531dcedec8339432dd40",
"mediaType": "application\/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 1570
}],
"mediaType": "application\/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}
manifest列表包含满足要求的各平台版本的镜像,同时指明镜像清单的版本,镜像清单有schemaV1、schemaV2、OCI多个版本,各版本差别在其他章节讲解。
4)筛选满足本平台要求的manifest Digest,请求远端仓库获取manifest文件,具体长这样:
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 7656,
"digest": "sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85"
},
"layers": [{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 31357624,
"digest": "sha256:a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 25350007,
"digest": "sha256:a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 602,
"digest": "sha256:589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 894,
"digest": "sha256:186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 666,
"digest": "sha256:b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 1395,
"digest": "sha256:a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2"
}
]
}
可以看到每个Layer层压缩数据的Digest
5)对manifest进行digest计算,生成镜像的Digest。
6)manifest包含config.digest字段,该字段为IMAGE ID,请求I模块判断是否已经存在同样的IMAGE ID,存在则返回。
7)请求下载manifest的各layer层数据,docker将请求任务放入消息队列,并设置并发下载数量,由统一的调度模块进行任务调度。
8)调用L模块存储下载完成的Layer数据,交给G模块进行存储,同时设置第一节涉及的DiffID、CacheID、ChainID以及descriptor信息、parent chainID信息等。
9)I模块Create 镜像,设置imagedb文件中的content内容,设置该image的关联的父子关系。
镜像下载流程大致如上,其中涉及多个模块,有的模块是基础存储服务模块,Image元数据增删改查、Layer层数据增删改查、Ref数据增删改查,有的模块是Docker处理逻辑模块,两类模块相互配合。