Creating your Private Docker Registry

While dealing with Docker containers, you typically pull images from a public registry like Docker Store or Docker Hub. There are some use case where you might want to use a local registry to pull images from, especially if you have proprietary code used in your custome images. As such, you have more control and security for your images and containers.

Fortunately, Docker makes it very easy to deploy a local Docker registry using the registry image, which can be found in Docker Hub.

By pulling and running a container from this image, you will have a fully functional local registry that your can use to pull and push images from and to.

In this post, two servers are acting as Docker hosts. On one server, we will get a local registry up and running using the image registry. We will then push some images to that local registry. On the second server, where no local image is available, we will use our local registry installed on the first server to pull some images.

We’re keeping things simple in this article as the goal is just to show the necessary steps to make a Docker local registry up and running. We’re not using any TLS certificate to secure the communication between Docker hosts and the registry. Bear in mind that using an insecure registry in production is not recommended. Only use this solution for isolated testing only.

Preparing the Prerequisites


First, we need to configure Docker to skip security checks for your registry on all your Docker hosts.

Create a file called daemon.json file in /etc/docker if it does not exist.

$ sudo vi /etc/docker/daemon.json

Then add the following content and save the file.

{
  "insecure-registries" : ["registry.local:5000"]
}

Finally, restart the Docker service to make this setting effective

$ sudo systemctl restart docker.service

We’ll also need to make sure the hostname resolution is working properly on both hosts. I have server1 and server2 used in this lab. My registry will be called registry.local and installed on server1, so the hosts file on both servers should look like this:

$ cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.16.21   server1.contoso.local   server1
192.168.16.22   server2.contoso.local   server2
192.168.16.21   registry.local

 

Installing the local registry


Start by pulling the registry from Docker Hub

$ docker pull registry

By default, the local registry is configured to start and listen on port 5000 in the container, and we will expose the host port also as 5000. To install a local registry named registry, and make it running in the background, it is as simple as running the following command.

$ docker run -d \
  -p 5000:5000 \
   --name registry \
   registry
  
  "59450661f226a2cb065e248dab73dcba52cd629cbeb2b6e77c725e6b68f1c144"

Check that the container is effectively running.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
59450661f226        registry            "/entrypoint.sh /etc…"   13 seconds ago      Up 11 seconds       0.0.0.0:5000->5000/tcp   registry

Our local registry up and running and we’re good to push to push images.

 

Pushing Images to the local registry


We have some images stored on our server, but these images are only visible to this host and we need to make them available to pull for other Docker hosts in our environment by pushing the ones we want to use to our local registry.

$ docker images
REPOSITORY          TAG            IMAGE ID            CREATED           SIZE
registry            latest         2e2f252f3c88        11 days ago       33.3MB
ubuntu              latest         cd6d8154f1e1        2 weeks ago       84.1MB
nginx               latest         06144b287844        2 weeks ago       109MB
php                 latest         4a05f96f44b5        4 weeks ago       367MB
busybox             latest         e1ddd7948a1c        7 weeks ago       1.16M

This will be done in two steps. The first one will be to tag the image with the REGISTRY_HOSTNAME:REGISTRY_PORT prefix. The command syntax is as below:

$ docker tag IMAGE_NAME REGISTRY_HOSTNAME:REGISTRY_PORT/CUSTOM_IMAGE_NAME

My registry name is registry.local. So to tag the ubuntu image as my-ubuntu, the command will be as follow:

$ docker tag ubuntu registry.local:5000/my-ubuntu

The image full name will be registry.local:5000/my-ubuntu

$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
registry                        latest              2e2f252f3c88        13 days ago         33.3MB
ubuntu                          latest              cd6d8154f1e1        2 weeks ago         84.1MB
registry.local:5000/my-ubuntu   latest              cd6d8154f1e1        2 weeks ago         84.1MB
nginx                           latest              06144b287844        2 weeks ago         109MB
...

The second step will be to push the image to the local registry using the following syntax.

$ docker push REGISTRY_HOSTNAME:REGISTRY_PORT/CUSTOM_IMAGE_NAME

Below command we’ll actually push the tagged registry.local:5000/my-ubuntu image to the local registry

$ docker push registry.local:5000/my-ubuntu

The push refers to repository [registry.local:5000/my-ubuntu]
8d7ea83e3c62: Pushed
6a061ee02432: Pushed
f73b2816c52a: Pushed
6267b420796f: Pushed
a30b835850bf: Pushed
latest: digest: sha256:a819482773d99bbbb570626b6101fa37cd93a678581ee564e89feae903c95f20 size: 1357

We now have a local registry with one image that can be pulled from any Docker host in our environment.

 

Pulling images to the local registry


On my second server, where there is no image available I should be able pull the ubuntu image pushed previously, but let’s make sure hostname resolution to registry.local is working fine.

$ hostname
server2.contoso.local

$ ping -c 3 registry.local
PING registry.local (192.168.16.21) 56(84) bytes of data.
64 bytes from server1.contoso.local (192.168.16.21): icmp_seq=1 ttl=64 time=1.40 ms
64 bytes from server1.contoso.local (192.168.16.21): icmp_seq=2 ttl=64 time=0.466 ms
64 bytes from server1.contoso.local (192.168.16.21): icmp_seq=3 ttl=64 time=0.574 ms

--- registry.local ping statistics ---
3 packets transmitted, 3 received, 0{a30ec6af4236f4179fdacbfa14163c342445d6f2c9798eae9caee1ef22a84454} packet loss, time 2004ms
rtt min/avg/max/mdev = 0.466/0.814/1.402/0.418 ms

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

Let’s pull my-ubuntu image from registry.local:5000

$ docker pull registry.local:5000/my-ubuntu
Using default tag: latest
latest: Pulling from my-ubuntu
124c757242f8: Pull complete
9d866f8bde2a: Pull complete
fa3f2f277e67: Pull complete
398d32b153e8: Pull complete
afde35469481: Pull complete
Digest: sha256:a819482773d99bbbb570626b6101fa37cd93a678581ee564e89feae903c95f20
Status: Downloaded newer image for registry.local:5000/my-ubuntu:latest

Image pulled successfully and is available now locally on the second Docker host.

$ docker images
REPOSITORY                      TAG         IMAGE ID          CREATED          SIZE
registry.local:5000/my-ubuntu   latest      cd6d8154f1e1      2 weeks ago      84.1MB

That’s it for this post. You have a fully functional private Docker registry that can be used in your environment. I a production environment, make sure your have a TLS certificate issues from a trusted CA for secure communication through HTTPS, and also attach a volume to your registry container to store your images in a permanent storage. My suggestion is to head over this Docker official documentation link and go through the content as it contains detailed information about this topic.

 

Leave a Comment

Your email address will not be published. Required fields are marked *