Understanding the Docker Registry Structure - Gitlab
Published: 2023-09-20 13:46:35

### Overview
With the Docker container registry image, Gitlab allows _the chosen few_ (Hail DevOps) to integrate a private container registry seamlessly. A couple of edits in the `gitlab.rb` file and you should be good to go.

The Docker container registry is a pretty stable and reliable piece of software which makes the life of a DevOps Engineer slightly easy. Although there would be some cases where you'd like to play with it. _(ensuring chaos ensues)_


![this-is-fine-fire.gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23fw6rfb3v4uj7747kuh.gif)

### Finding the treasure
When the Container Registry Image is run by default the `rootdirectory` set as `/var/docker/registry`. Which should be the same in most cases.

On mild forensics the file structure comes out to be as shown as below - 

```
- /var/docker/registry
    - v2
        - blobs
        - repositories
```

`v2` corresponds to the Docker Registry API version which Version 2 in this case.

On further digging the `repositories` directory hosts the following sub-directories - 

```
- repositories
    - gitlab-test-user
        - gitlab-test-repo
            - _layers
            - _manifests
                - revisions
                - tags
                    - sample-tag
                        - current
                            - link
                        - index
            _ _uploads

```

Phew! That's a long list, but the most important of all is the `link` component. The link itself is not the image but an ID.

_"Then where is the Image?"_, you ask.

The "Image Data" is stored in the blobs directory under the `v2` directory. Opening up blobs gives us the this -

```
- blobs
    - sha256
        - 3b
        - cb
        - f6
            - f662ea83eddb8ce7e979cb6c09527feace32d32500e027fa87bf5362d732af16
                - data
```

Haha, Finally the data!
_Uhmmm not yet._

```
{
	"schemaVersion": 2,
	"mediaType": "application/vnd.docker.distribution.manifest.v2+json"
	"config": {
		"mediaType": "application/vnd.docker.container.image.v1+json"
		"size": 1619,
		"digest"; "sha256:3b0372d60921e1cc0c017732ff6d41f8e4880246a6d9c8c9d101edc1726a79ab"
	},
	"layers": [
		{
			"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
			"size": 2813316,
			"digest": "sha256:cbdbe7a5bc2a134caBec91be58565ec07d037386d1f1d8385412d224deafca08"
		}
	]
}
```
This is rather a JSON document containing details of the image.

The config digest `("sha256:3b0372d60921e1cc0c017732ff6d41f8e4880246a6d9c8c9d101edc1726a79ab")` is a link to a document that will instruct docker on how to build the image. It can be found under `blobs/sha256/3b`.

One thing to understand is that a Docker Image is not a single chunk of data rather it is a collection of layers. This is a really efficient technique to store data as this helps in not storing redundant pieces of information as we will see later.

Now moving on to the second part of the above "data" file is the link to where the layers of the image are stored. Here we have the digest as `"sha256: cbdbe7a5bc2a134caBec91be58565ec07d037386d1f1d8385412d224deafca08"` which again can be found under `blobs/sha256/cb`, you can now see the Image in its layers form. Since we have only one layer here, that itself is the image or rather the ingredient of the image which will be used by docker to create the image.

The layers themselves are single pieces but when combined make up the image. This helps in saving up space.

Take a scenario where the same image is being pushed into the registry, this time rather than again storing the redundant piece of data, docker will link to the same `image layer` as the previous one. Saving us with some space.

Considering the case where the are some changes to the image and is pushed to the same or a different repository, docker will create a new layer which is the `diff` (just the modified part) part of the new image and simply create a link and add this to the configuration file which we saw earlier.

```
{
	"schemaVersion": 2,
	"mediaType": "application/vnd.docker.distribution.manifest.v2+json"
	"config": {
		"mediaType": "application/vnd.docker. container. image.v1+json"
		"size": 1619,
		"digest"; "sha256:3b0372d60921e1cc0c017732ff6d41f8e4880246a6d9c8c9d101edc1726a79ab"
	},
	"layers": [
		{
			"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
			"size": 2813316,
			"digest": "sha256:cbdbe7a5bc2a134caBec91be58565ec07d037386d1f1d8385412d224deafca08"
		},
		{
			"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
			"size": 109,
			"digest": "sha256:5110abe04d9e848d121feb3cc36dd0ec20465f6f67f6dc49699ea408bc244188"
		}
	]
}
```
The modified part of the image forms a new layer and the link to that layer has been added to the file.

Summing up, whenever we do a `docker pull` to the registry it will go and fetch the link under the respective repository, which points towards the manifest file in blobs containing the recipe (instructions) and the ingredients (layers) which docker will then use to make the image.

For further explanation - [Reference](https://www.youtube.com/watch?v=i5mbF2bgWoM)

![Thanks](https://media.tenor.com/EVm6yB9MGTgAAAAd/grazie-inglorious.gif)