Docker: How to Run Your Own Docker Registry (e.g. Images Repository)

root's picture

You know how to pull and create custom images; do whatever with them.
But if you need the same custom image on multiple servers in your network, you will have to copy that image on them. Here comes docker registry: a local repository of your images.
And the installation of a local repository is done via (guess?) a container :).
Basically, all you have to do is to pull the registry image and run a container on top of it. As simple as that!

Pull the registry image:

10:43:22 root@service:~# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
c87736221ed0: Pull complete 
1cc8e0bb44df: Pull complete 
54d33bcb37f5: Pull complete 
e8afc091c171: Pull complete 
b4541f6d3db6: Pull complete 
Digest: sha256:3b00e5438ebd8835bcfa7bf5246445a6b57b9a50473e89c02ecc8e575be3ebb5
Status: Downloaded newer image for registry:latest

Create and start a container with the registry image:

10:49:52 root@service:~# docker run -d -p 5000:5000 --restart=always --name repo registry
d773997bbe351142fecd1b14c86a8aa7dd838cb392adc83b697a5a454b175819
10:53:32 root@service:~# docker container ls | grep repo
d773997bbe35        registry                     "/entrypoint.sh /etc…"   17 seconds ago      Up 13 seconds       0.0.0.0:5000->5000/tcp   repo

At this point, you have a running local images repository and you can push images to it.

Prepare an image to be stored on your registry.

root@uranus:~# docker images | grep mediashow
mediashow                          orig                ea1528ea8c5d        4 days ago          689MB
root@uranus:~# docker tag mediashow:orig service:5000/mediashow
root@uranus:~# docker images | grep mediashow
mediashow                          orig                ea1528ea8c5d        4 days ago          689MB
service:5000/mediashow             latest              ea1528ea8c5d        4 days ago          689MB

If you want to push the image locally, you need to tag the target image with localhost:PORT. In this example, we will not push this image locally and for that we would need ssl.
However, for very private network (like I have), you can choose to use registry via http (not https) or with self signed certificate.
To speed up, let’s push our image without encryption: edit /etc/docker/daemon.json (create it if it does not exist) for every client that wants to access this repo, by adding the following and restart docker.

{
  "insecure-registries" : ["iporhostname:5000"]
}

Example:

The command fails because the client wants to push the image via https:

root@uranus:~# docker push service:5000/mediashow
The push refers to repository [service:5000/mediashow]
Get https://service:5000/v2/: http: server gave HTTP response to HTTPS client

Add in the configuration file /etc/docker/daemon.json the hostname and port of your registry and restart docker:

root@uranus:~# nano /etc/docker/daemon.json
root@uranus:~# cat /etc/docker/daemon.json
{
"insecure-registries" : ["service:5000"]
}
root@uranus:~# /etc/init.d/docker restart
[ ok ] Restarting docker (via systemctl): docker.service.

Now it works:

root@uranus:~# docker push service:5000/mediashow
The push refers to repository [service:5000/mediashow]
cb1685712647: Pushed 
5bb0785f2eee: Pushed 
latest: digest: sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d size: 742

On the node where the registry is running, you do not need to set up "insecure-registries":

21:47:13 root@service:~# docker pull service:5000/mediashow
Using default tag: latest
latest: Pulling from mediashow
22dbe790f715: Already exists 
9b16e8d3c72e: Pull complete 
Digest: sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d
Status: Downloaded newer image for service:5000/mediashow:latest
21:49:05 root@service:~# docker images | grep mediashow
service:5000/mediashow   latest              ea1528ea8c5d        4 days ago          689MB

You have your first image stored on your repo. How do you list it?
At this moment you cannot do it out of the box but fortunately there is an api for it.
Details here.

Example of listing with curl:

root@uranus:~# curl http://service:5000/v2/_catalog
{"repositories":["mediashow"]}

Useful tips

How to cleanup the registry (delete untagged manifest tags):

19:43:25 root@service:teamcity# docker exec repo bin/registry garbage-collect /etc/docker/registry/config.yml -m
mediashow
mediashow: marking manifest sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d 
mediashow: marking blob sha256:ea1528ea8c5d9d6a702a6cd921d84d35162eecb820870e204f22132e792bfae1
mediashow: marking blob sha256:22dbe790f71562dfd3d49406b1dfd1e85e50f3dd7cb2e97b3918376ca39cae4e
mediashow: marking blob sha256:9b16e8d3c72ea84d227ad6cbed713b0da0d7cdb07467d69cb1bb1dca108a36d1
test-debian
test-debian: marking manifest sha256:9a1b6b1073bf12428a55c54e6e3bb001946afbcf49b7fea6a02d345790356998 
test-debian: marking blob sha256:2d337f242f078dfa62c81db584e78e33fd6bf6138875ecfb11fa470f26a5411c
test-debian: marking blob sha256:e79bb959ec00faf01da52437df4fad4537ec669f60455a38ad583ec2b8f00498
test-nginx
manifest eligible for deletion: sha256:3ace5804ba527f2f903b406ecb56e38d26b293cdb646a91384064529c8d08d07
test-nginx: marking manifest sha256:6b9398bdcde314a5d13150089a09d6b1e513c1b58902742ff9c73d96e9013146 
test-nginx: marking blob sha256:bfa32062f76e87db17b14ea3219f9fad4a33d518dc916b38e7d4635079a53653
test-nginx: marking blob sha256:27833a3ba0a545deda33bb01eaf95a14d05d43bf30bce9267d92d17f069fe897
test-nginx: marking blob sha256:e83729dd399a6091566a1c24b1d8543a7b34ce4a0c4896ab91fb55d1e68a90e1
test-nginx: marking blob sha256:ebc6a67df66d530738103d6c4299b47236290db1004365fcef9abb65f017de3d
manifest eligible for deletion: sha256:b8ea03af22fcd06236734169732e74c897367e20d657c82d7853c01a8fe6ec72
manifest eligible for deletion: sha256:ee8b7a566544d4e736f7ee7ef78a057280478d0ac698a8705840a49c92ec0b61
time="2019-04-06T17:43:34.19342756Z" level=info msg="deleting manifest tag reference: /docker/registry/v2/repositories/test-nginx/_manifests/tags/BETA/index/sha256/3ace5804ba527f2f903b406ecb56e38d26b293cdb646a91384064529c8d08d07" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
time="2019-04-06T17:43:34.194565308Z" level=info msg="deleting manifest: /docker/registry/v2/repositories/test-nginx/_manifests/revisions/sha256/3ace5804ba527f2f903b406ecb56e38d26b293cdb646a91384064529c8d08d07" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
time="2019-04-06T17:43:34.19494823Z" level=info msg="deleting manifest tag reference: /docker/registry/v2/repositories/test-nginx/_manifests/tags/BETA/index/sha256/b8ea03af22fcd06236734169732e74c897367e20d657c82d7853c01a8fe6ec72" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
time="2019-04-06T17:43:34.195213311Z" level=info msg="deleting manifest: /docker/registry/v2/repositories/test-nginx/_manifests/revisions/sha256/b8ea03af22fcd06236734169732e74c897367e20d657c82d7853c01a8fe6ec72" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
time="2019-04-06T17:43:34.195468585Z" level=info msg="deleting manifest tag reference: /docker/registry/v2/repositories/test-nginx/_manifests/tags/BETA/index/sha256/ee8b7a566544d4e736f7ee7ef78a057280478d0ac698a8705840a49c92ec0b61" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
time="2019-04-06T17:43:34.195780136Z" level=info msg="deleting manifest: /docker/registry/v2/repositories/test-nginx/_manifests/revisions/sha256/ee8b7a566544d4e736f7ee7ef78a057280478d0ac698a8705840a49c92ec0b61" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 

12 blobs marked, 6 blobs and 3 manifests eligible for deletion
blob eligible for deletion: sha256:d871b7b23b0af198ab4328b6578eb4117323d8e42e5eaf064090d40510519216
time="2019-04-06T17:43:34.205777733Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/d8/d871b7b23b0af198ab4328b6578eb4117323d8e42e5eaf064090d40510519216" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
blob eligible for deletion: sha256:ee8b7a566544d4e736f7ee7ef78a057280478d0ac698a8705840a49c92ec0b61
time="2019-04-06T17:43:34.206580444Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/ee/ee8b7a566544d4e736f7ee7ef78a057280478d0ac698a8705840a49c92ec0b61" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
blob eligible for deletion: sha256:152775d22d07e8fad0304843bd4ef9e88e6b569d5b7257b612123e4ad1555bbe
time="2019-04-06T17:43:34.207033657Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/15/152775d22d07e8fad0304843bd4ef9e88e6b569d5b7257b612123e4ad1555bbe" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
blob eligible for deletion: sha256:3ace5804ba527f2f903b406ecb56e38d26b293cdb646a91384064529c8d08d07
time="2019-04-06T17:43:34.207606997Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/3a/3ace5804ba527f2f903b406ecb56e38d26b293cdb646a91384064529c8d08d07" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
blob eligible for deletion: sha256:86810dd72dba239d09f8e9bc2a259adf4fa92000be320908718aeb7fe09121eb
time="2019-04-06T17:43:34.208304654Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/86/86810dd72dba239d09f8e9bc2a259adf4fa92000be320908718aeb7fe09121eb" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry 
blob eligible for deletion: sha256:b8ea03af22fcd06236734169732e74c897367e20d657c82d7853c01a8fe6ec72
time="2019-04-06T17:43:34.220267253Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/b8/b8ea03af22fcd06236734169732e74c897367e20d657c82d7853c01a8fe6ec72" go.version=go1.11.2 instance.id=7210b30c-6fdb-4eb7-a463-c19bc399ed3d service=registry

Second run is not deleting anything:

19:44:01 root@service:teamcity# docker exec repo bin/registry garbage-collect /etc/docker/registry/config.yml -m
mediashow
mediashow: marking manifest sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d 
mediashow: marking blob sha256:ea1528ea8c5d9d6a702a6cd921d84d35162eecb820870e204f22132e792bfae1
mediashow: marking blob sha256:22dbe790f71562dfd3d49406b1dfd1e85e50f3dd7cb2e97b3918376ca39cae4e
mediashow: marking blob sha256:9b16e8d3c72ea84d227ad6cbed713b0da0d7cdb07467d69cb1bb1dca108a36d1
test-debian
test-debian: marking manifest sha256:9a1b6b1073bf12428a55c54e6e3bb001946afbcf49b7fea6a02d345790356998 
test-debian: marking blob sha256:2d337f242f078dfa62c81db584e78e33fd6bf6138875ecfb11fa470f26a5411c
test-debian: marking blob sha256:e79bb959ec00faf01da52437df4fad4537ec669f60455a38ad583ec2b8f00498
test-nginx
test-nginx: marking manifest sha256:6b9398bdcde314a5d13150089a09d6b1e513c1b58902742ff9c73d96e9013146 
test-nginx: marking blob sha256:bfa32062f76e87db17b14ea3219f9fad4a33d518dc916b38e7d4635079a53653
test-nginx: marking blob sha256:27833a3ba0a545deda33bb01eaf95a14d05d43bf30bce9267d92d17f069fe897
test-nginx: marking blob sha256:e83729dd399a6091566a1c24b1d8543a7b34ce4a0c4896ab91fb55d1e68a90e1
test-nginx: marking blob sha256:ebc6a67df66d530738103d6c4299b47236290db1004365fcef9abb65f017de3d

12 blobs marked, 0 blobs and 0 manifests eligible for deletion

How to delete an image from registry:

00:23:44 root@service:services# curl -X GET service:5000/v2/_catalog
{"repositories":["mediashow","test-debian","test-nginx"]}
00:23:59 root@service:services# curl -X GET service:5000/v2/mediashow/tags/list
{"name":"mediashow","tags":["latest"]}
00:24:09 root@service:services# curl -v --silent -X GET http://localhost:5000/v2/mediashow/manifests/latest 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'
sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d
00:24:29 root@service:services# curl -X DELETE service:5000/v2/mediashow/manifests/sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d

Now you can wait for garbage collect to do automatic cleanup or you can run it yourself:

00:25:10 root@service:services# docker exec repo bin/registry garbage-collect /etc/docker/registry/config.yml -m
mediashow
test-debian
test-debian: marking manifest sha256:9a1b6b1073bf12428a55c54e6e3bb001946afbcf49b7fea6a02d345790356998 
test-debian: marking blob sha256:2d337f242f078dfa62c81db584e78e33fd6bf6138875ecfb11fa470f26a5411c
test-debian: marking blob sha256:e79bb959ec00faf01da52437df4fad4537ec669f60455a38ad583ec2b8f00498
test-nginx
test-nginx: marking manifest sha256:3aa720c26384fa3b6ae2f7401e9d411bbe710ac0c1ba6ac67b9775aabf531ccd 
test-nginx: marking blob sha256:0ccc1d043322a5bd9ebbba87ba260edee9fab1d2fd26bac7e1c04216e8f6b531
test-nginx: marking blob sha256:27833a3ba0a545deda33bb01eaf95a14d05d43bf30bce9267d92d17f069fe897
test-nginx: marking blob sha256:e83729dd399a6091566a1c24b1d8543a7b34ce4a0c4896ab91fb55d1e68a90e1
test-nginx: marking blob sha256:ebc6a67df66d530738103d6c4299b47236290db1004365fcef9abb65f017de3d

8 blobs marked, 5 blobs and 0 manifests eligible for deletion
blob eligible for deletion: sha256:22dbe790f71562dfd3d49406b1dfd1e85e50f3dd7cb2e97b3918376ca39cae4e
time="2019-04-06T22:25:20.206019452Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/22/22dbe790f71562dfd3d49406b1dfd1e85e50f3dd7cb2e97b3918376ca39cae4e" go.version=go1.11.2 instance.id=57a0e610-b95a-42ec-8c32-c18067bf657a service=registry 
blob eligible for deletion: sha256:7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d
time="2019-04-06T22:25:20.211766082Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/7c/7c0aef710a8c7ebed5ac6ecb92053f1acc57d87451e825030685344fc65ce06d" go.version=go1.11.2 instance.id=57a0e610-b95a-42ec-8c32-c18067bf657a service=registry 
time="2019-04-06T22:25:20.212306909Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/9b/9b16e8d3c72ea84d227ad6cbed713b0da0d7cdb07467d69cb1bb1dca108a36d1" go.version=go1.11.2 instance.id=57a0e610-b95a-42ec-8c32-c18067bf657a service=registry 
blob eligible for deletion: sha256:9b16e8d3c72ea84d227ad6cbed713b0da0d7cdb07467d69cb1bb1dca108a36d1
blob eligible for deletion: sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
time="2019-04-06T22:25:20.254861777Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/a3/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" go.version=go1.11.2 instance.id=57a0e610-b95a-42ec-8c32-c18067bf657a service=registry 
time="2019-04-06T22:25:20.255666973Z" level=info msg="Deleting blob: /docker/registry/v2/blobs/sha256/ea/ea1528ea8c5d9d6a702a6cd921d84d35162eecb820870e204f22132e792bfae1" go.version=go1.11.2 instance.id=57a0e610-b95a-42ec-8c32-c18067bf657a service=registry 
blob eligible for deletion: sha256:ea1528ea8c5d9d6a702a6cd921d84d35162eecb820870e204f22132e792bfae1

NOTE: the image will be deleted but the catalog entry will still be listed.

00:25:20 root@service:services# curl -X GET service:5000/v2/_catalog
{"repositories":["mediashow","test-debian","test-nginx"]}

There is however a way to delete the entry but it is a bit tricky. You will need to go to the directory where the repository files are kept and delete the folder that holds was holding your deleted image. Then it will no more be listed when running again the above command.

Useful links:

https://docs.docker.com/registry/
https://docs.docker.com/registry/insecure/
https://docs.docker.com/registry/spec/api/#listing-repositories
https://docs.docker.com/registry/spec/api/#deleting-an-image

Thou shalt not steal!

If you want to use this information on your own website, please remember: by doing copy/paste entirely it is always stealing and you should be ashamed of yourself! Have at least the decency to create your own text and comments and run the commands on your own servers and provide your output, not what I did!

Or at least link back to this website.

Recent content