首先,我们用docker官网的library/registry:2.5.0
在本地搭建一个私有镜像仓库,然后把该镜像本身上传到私有镜像仓库中。
镜像仓库挂载到本地的根目录为/data/registry
,我们查看上传library/registry:2.5.0
镜像后的目录树:
Copy /data/registry/
└── docker
└── registry
└── v2
├── blobs
│ └── sha256
│ ├── 06
│ │ └── 06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a
│ │ └── data
│ ├── 2e
│ │ └── 2ee5ed28ffa762104505295c3c256c52a87fe8af0114b9e0198e9036495e10b8
│ │ └── data
│ ├── 51
│ │ └── 51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
│ │ └── data
│ ├── 80
│ │ └── 802d2a9c64e8f556e510b4fe6c5378b9d49d8335a766d156ef21c7aeac64c9d6
│ │ └── data
│ ├── c6
│ │ └── c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
│ │ └── data
│ ├── d1
│ │ └── d1562c23a8aa4913a2fc720a3c478121f45d26597b58bbf9a29238276ca420a7
│ │ └── data
│ └── e1
│ └── e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
│ └── data
└── repositories
└── library
└── registry
├── _layers
│ └── sha256
│ ├── 06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a
│ │ └── link
│ ├── 2ee5ed28ffa762104505295c3c256c52a87fe8af0114b9e0198e9036495e10b8
│ │ └── link
│ ├── 802d2a9c64e8f556e510b4fe6c5378b9d49d8335a766d156ef21c7aeac64c9d6
│ │ └── link
│ ├── c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
│ │ └── link
│ ├── d1562c23a8aa4913a2fc720a3c478121f45d26597b58bbf9a29238276ca420a7
│ │ └── link
│ └── e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
│ └── link
├── _manifests
│ ├── revisions
│ │ └── sha256
│ │ └── 51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
│ │ └── link
│ └── tags
│ └── 2.5.0
│ ├── current
│ │ └── link
│ └── index
│ └── sha256
│ └── 51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
│ └── link
└── _uploads
数据都在/data/registry/docker/registry/v2
下,接下来我们使用的相对路径都是在该目录下。
blobs
blobs目录下存储着所有的layer压缩包。根据《镜像的本地存储》一文可以知道,library/registry:2.5.0
只有五个layer,分别是blobs目录下的
Copy 06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a
2ee5ed28ffa762104505295c3c256c52a87fe8af0114b9e0198e9036495e10b8
802d2a9c64e8f556e510b4fe6c5378b9d49d8335a766d156ef21c7aeac64c9d6
d1562c23a8aa4913a2fc720a3c478121f45d26597b58bbf9a29238276ca420a7
e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
这五个目录下的data文件是二进制文件。对这些二进制文件的内容做sha256哈希,得到的哈希值就是目录的名字。比如:
Copy $ sha256sum blobs/sha256/e1/e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58/data
e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
对这些data文件解压,得到的就是该layer的文件系统(目录与文件),比如:
Copy $ mkdir layer
$ tar xzf blobs/sha256/e1/e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58/data -C layer
$ ll layer/
total 12
drwxr-xr-x. 2 root root 4096 Jun 24 2016 bin
drwxr-xr-x. 4 root root 40 Jun 24 2016 dev
drwxr-xr-x. 14 root root 4096 Jun 24 2016 etc
drwxr-xr-x. 2 root root 6 Jun 24 2016 home
drwxr-xr-x. 5 root root 188 Jun 24 2016 lib
lrwxrwxrwx. 1 root root 12 Jun 24 2016 linuxrc -> /bin/busybox
drwxr-xr-x. 5 root root 44 Jun 24 2016 media
drwxr-xr-x. 2 root root 6 Jun 24 2016 mnt
drwxr-xr-x. 2 root root 6 Jun 24 2016 proc
drwx------. 2 root root 6 Jun 24 2016 root
drwxr-xr-x. 2 root root 6 Jun 24 2016 run
drwxr-xr-x. 2 root root 4096 Jun 24 2016 sbin
drwxr-xr-x. 2 root root 6 Jun 24 2016 srv
drwxr-xr-x. 2 root root 6 Jun 24 2016 sys
drwxrwxrwt. 2 root root 6 Jun 24 2016 tmp
drwxr-xr-x. 7 root root 66 Jun 24 2016 usr
drwxr-xr-x. 12 root root 125 Jun 24 2016 var
值得注意的是,虽然我们可以用tar命令把layer压缩包解压,但是解压后我们用tar命令重新压缩tar czvf layer.tar.gzip layer/*
,再对压缩后的layer.tar.gzip做sha256哈希,得到的hash值与直接对data做哈希得到的值不一样。实验证明不是文件名的问题,对data文件重命名,哈希值都是一样的,因为哈希是对文件内容做的,与文件名无关。猜测是data的打包压缩方式与直接用tar命令不一样。
blobs目录下除了上述五个目录外,还有另外两个:
Copy c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
如果我们在某台主机上下载该镜像,会发现 c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
就是镜像library/registry:2.5.0
的image-id,51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
就是镜像的digest。
Copy $ docker images --digests --no-trunc
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
192.168.1.103:8021/library/registry 2.5.0 sha256:51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6 sha256:c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98 2 years ago 33.31 MB
image-id是镜像的config文件的哈希值:
Copy $ sha256sum blobs/sha256/c6/c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98/data
c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
查看镜像的config文件的内容(不要用cat
命令,用jq . blobs/sha256/c6/c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98/data
命令可以格式化输出,方便查看):
从config文件可以看出,library/registry:2.5.0
有五个layer。不过在该文件里,使用的是layer的diffid。
image-digest是镜像的manifest文件的哈希值:
Copy $ sha256sum blobs/sha256/51/51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6/data
51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
查看digest文件的内容如下(与查看config文件一样的命令查看):
从manifest文件也同样可以看出,镜像library/registry:2.5.0
有五个layer。只不过在该文件里,使用的是layer的digest。从mediaType
字段可以看出,blobs目录下面layer的data文件是经过tar及gzip算法进行了打包与压缩的。
这里讲一下layer的diffid与digest的区别:
layer-diffid:未压缩的layer打包文件的哈希值
layer-digest:压缩后的layer打包文件的哈希值
repositories
我们上传镜像library/registry:2.5.0
后,便会在repositories目录下生成library/registry
目录。接下来我们都以 repositories/library/registry
作为当前路径 。
该目录下有三个目录 _layers
、_manifests
、_uploads
。
_layers
目录下存储了该repository的所有layer的索引(layer-digest)以及所有的image的索引(image-id)。例如,我们查看某个layer下link文件的内容及image-id下link文件的内容如下:
Copy $ cat _layers/sha256/e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58/link
sha256:e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
$ cat _layers/sha256/c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98/link
sha256:c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
link文件的内容指向blobs中的实际数据。
registry的API-v2中,下载layer的接口为GET /v2/{repository}/blobs/{layer-digest}
,根据路径参数repository
与layer-digest
,就可以在repositories/{repository}/_layers
目录下搜索layer-digest
,然后去blobs目录下下载。
_manifests
目录下存储的实际是镜像的digest以及镜像的tag到digest的映射关系。revisions/
下存储的就是image-digest,tags/
下就是tag到image-digest的映射。
目录树如下:
Copy $ tree _manifests
_manifests/
├── revisions
│ └── sha256
│ └── 51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
│ └── link
└── tags
└── 2.5.0
├── current
│ └── link
└── index
└── sha256
└── 51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
└── link
上面三个link文件的内容全部是sha256:51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
,就是镜像library/registry:2.5.0
的image-digest,指向实际的manifest文件blobs/sha256/51/51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
。
在registry的API-v2中,下载镜像的manifest文件的接口为GET /v2/{repository}/mainfests/{tag_or_digest}
。如果提供是的是tag 2.5.0
,根据tags/2.5.0/current/link
文件的内容,得到的manifest文件为blobs/sha256/51/51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
;如果提供是的digest sha256:51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
,根据revisions/sha256/51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6/link
文件的内容,得到的manifest文件还是blobs/sha256/51/51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
。