Hosting your first Private Docker Registry
A registry is a stateless, highly scalable server side application that stores and lets you distribute Docker images. At a high level, a registry is a collection of different repositories which contain our images. These images have different tags.
In this article we will be talking about:
- What is a Registry?
- Running our first Private Registry
- Interacting with Registry
- Pushing an image
- Pulling the new image
What is a Registry?
A registry is a stateless, highly scalable server side application that stores and lets you distribute Docker images. At a high level, a registry is a collection of different repositories which contain our images. These images have different tags.
We generally use a private registry when we want to:
- keep control of the distribution of images
- control where the images are stored
- integrate image storage and distribution tightly into your in-house development workflow
Running our first Private Registry
Before we start to deploy a registry, ensure that Docker is installed on the host machine. A registry server is based on the registry
image. To get more details about the image, checkout DockerHub.
Let’s spin up our first registry container using the following command:
|
|
If you don’t get any errors (which you probably will not), then you should see something like the following:
Just in case, there is another container or process using port 5000
you might get an error like:
|
|
To fix that, all we need is to change the port from 5000
to something else, like 8000
or whichever is available.
|
|
And this time things should workout.
Now that our registry is up and running, we can use the Docker Registry HTTP API V2 to interact with our running instance. We will using this API to get the list of repositories and list of tags of a particular repository. For details on Docker Registry HTTP API, please check the docs.
So, let’s open up a browser, and go to http://localhost:5000/v2/_catalog/ and what we get is a list of repositories returned from our registry instance as a JSON response.
Note that if you are not hosting the registry locally, you need to use the IP address of registry host instead of localhost
.
For instance, http://13.233.122.144:5000/v2/_catalog/
and you should see something like:
Notice that our list of repositories is empty. This is because we have not yet pushed any image to our registry. Let’s do that next.
Pushing a Docker Image
Before we push our first image I want you to note that we had started our registry container with -it
options.
This means that we can’t use the same terminal to interact with the registry. So, we have three options here:
- open up a new terminal for further interactions and use the current one to observe the logs
- press the keys
ctl+pq
(control + pq) which will leave our registry container running in detached mode and return terminal control - stop the current instance by pressing the
ctl+c
keys and run the following commands:
|
|
Now, let’s write a Dockerfile to create our own image. Here is mine, a simple one:
|
|
We can now build our image using the command:
|
|
If you are building the image on a host other than the one hosting our registry server, replace localhost
with the IP of hostname of the registry host.
To make things clean, let’s add different tags to our image and push it to the registry:
|
|
How do we verify that the push was successful?
Well we have got the Docker Registry HTTP API V2 that is used to interact with the registry server. Let’s see that next.
Interacting with Registry Server
To interact with the registry server we can use the Docker Registry HTTP API V2. Open a browser and go to _http://REGISTRY-HOST-IP:5000/v2/catalog/ . If you are hosting at a different port, then use that port instead of 5000. What we get is a list of repositories as a JSON response, and it should look like:
|
|
We can also list out different tags of an image, by making a tags list request, as shown below. This gives us a list of tags added to my-busybox as a JSON result:
|
|
The V2 API exposes different endpoints that allow us to perform different operations on an image or interact with registry itself. You read more about it from the docs.
Pulling an Image
In order to understand the flow, we will now switch to another host that has Docker installed on it and can communicate with the registry host. On the second host, try to pull the my-busybox image from the registry and you should get an error as shown below:
|
|
In order to understand the reason for the above error, let’s run the docker info
command and notice the Registry and Insecure Registries section, at the end.
|
|
As it can be seen in the output, the default registry for Docker is Docker Hub. Docker first tries to search for an image in the local filesystem and if the image is not available, it goes looking for it at the Docker Hub. To make Docker aware about our insecure registry, we have to add a daemon.json
file with an entry of our registry server.
|
|
Now, if we run the docker info
command again and notice the Insecure Registries section, it will have an entry for our registry server. Let’s try to pull the image again, and it will be successful.
|
|
We can now spin-up a container using the image we just pulled. Here I’m executing the top
command in container and piping its output to my standard output with the -it
options.
|
|
Congratulations!! We have setup our first registry server and have successfully pushed and pulled an image from it.
Conclusion
In this article, we have setup an insecure Docker registry and we have also seen how we can push and pull images from it. While this registry works well for testing purpose, it is not ready for production in any way.