# Registry中的存储

首先，我们用docker官网的`library/registry:2.5.0`在本地搭建一个私有镜像仓库，然后把该镜像本身上传到私有镜像仓库中。

镜像仓库挂载到本地的根目录为`/data/registry`，我们查看上传`library/registry:2.5.0`镜像后的目录树：

```
/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目录下的

```
06ba8e23299fcf9dd9efb3c5acd4c9d03badac5392953001c75d38197113a63a
2ee5ed28ffa762104505295c3c256c52a87fe8af0114b9e0198e9036495e10b8
802d2a9c64e8f556e510b4fe6c5378b9d49d8335a766d156ef21c7aeac64c9d6
d1562c23a8aa4913a2fc720a3c478121f45d26597b58bbf9a29238276ca420a7
e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
```

这五个目录下的data文件是二进制文件。对这些二进制文件的内容做sha256哈希，得到的哈希值就是目录的名字。比如：

```
$ sha256sum blobs/sha256/e1/e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58/data
e110a4a1794126ef308a49f2d65785af2f25538f06700721aad8283b81fdfa58
```

对这些data文件解压，得到的就是该layer的文件系统（目录与文件），比如：

```
$ 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目录下除了上述五个目录外，还有另外两个：

```
c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98
51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6
```

如果我们在某台主机上下载该镜像，会发现 `c6c14b3960bdf9f5c50b672ff566f3dabd3e450b54ae5496f326898513362c98`就是镜像`library/registry:2.5.0`的image-id，`51d8869caea35f58dd6a2309423ec5382f19c4e649b5d2c0e3898493f42289d6`就是镜像的digest。

```
$ 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文件的哈希值：

```
$ 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文件的哈希值：

```
$ 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

`_layers`目录下存储了该repository的所有layer的索引（layer-digest）以及所有的image的索引（image-id）。例如，我们查看某个layer下link文件的内容及image-id下link文件的内容如下：

```
$ 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

`_manifests`目录下存储的实际是镜像的digest以及镜像的tag到digest的映射关系。`revisions/`下存储的就是image-digest，`tags/`下就是tag到image-digest的映射。

目录树如下：

```
$ 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`。
