This is the very first article on this blog about Docker. And I can’t tell you how excited I’m to write it. This is the very beginning of a whole new journey. Alright then, let’s get started.CodeProject
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:
docker run -it -p 5000:5000 --name registry registry:2.7
If you don’t get any errors (which you probably will not), then you should see something like the following:
Running the first Registry Server
Just in case, there is another container or process using port
5000 you might get an error like:
ubuntu@docker:~$ docker run -it -p 5000:5000 --name registry registry:2.7
docker: Error response from daemon: driver failed programming external
connectivity on endpoint registry (2793fe2664b4f202c4ab4bb017c8073b812d643904e62426814f5aa60b44dfa5):
Bind for 0.0.0.0:5000 failed: port is already allocated.
To fix that, all we need is to change the port from
5000 to something else, like
8000 or whichever is available.
docker run -it -p <new-port>:5000 --name registry registry:2.7
And this time things should workout.
Note that these steps are to setup a registry for testing purpose only. A production-ready registry must be protected by TLS and should ideally have an access-control mechanism.
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://22.214.171.124:5000/v2/_catalog/ and you should see something like:
Repositories in our Registry
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:
docker container rm registry
docker run -d -p 5000:5000 --name registry registry:2.7
Now, let’s write a Dockerfile to create our own image. Here is mine, a simple one:
LABEL Author="Gaurav Gahlot"
We can now build our image using the command:
docker build -t localhost:5000/my-busybox .
Note that, 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. We can now push the image to our registry, using the following command:
$ docker tag localhost:5000/my-busybox localhost:5000/my-busybox:v1
$ docker tag localhost:5000/my-busybox localhost:5000/my-busybox:custom
$ docker push localhost:5000/my-busybox
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 going to the URL http://REGISTRY-HOST-IP:5000/v2/my-busybox/tags/list. 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:
$ docker pull <registry-host-ip>:5000/my-busybox
Using default tag: latest
Error response from daemon: Get https:
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.
$ docker info
Live Restore Enabled: false</snip>
As it can be seen in the output, the default registry for Docker is docker.io (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.
$ nano /etc/docker/daemon.json
$ service docker restart
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.
$ docker pull <registry-host-ip>:5000/my-busybox
Using default tag: latest
latest: Pulling from <registry-host-ip>:5000/my-busybox
697743189b6d: Pull complete
Status: Downloaded newer image for <registry-host-ip>:5000/my-busybox:latest</registry-host-ip></registry-host-ip></registry-host-ip>
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 option
docker run -it --rm --name my-container REGISTRY-HOST-localhost:5000/my-busybox top
Congratulations!! We have setup our first registry server and have successfully pushed and pulled an image from it.
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. In upcoming articles, we will see how we can improve our registry to store data in a named volume and secure our registry with basic authentication.
The post Hosting your first Private Docker Registry appeared first on Quick Dev Notes.