In the previous part, we’ve learned how to utilize Docker Compose to tie multiple containers together with a single command. We’ve added a MySQL database to our ASP.NET Core application and successfully run it.

Before proceeding further to Continuous Integration parts, we need to learn more about image management and distribution. There are several ways to do that, whether locally or in the cloud, so you should definitely know these concepts before starting with continuous integration.

In this part, we are going to learn the difference between a Docker registry and a Docker repository and how to persist the changes we made to our images. We’re also going to learn more about Docker Hub and how to make our own local Docker registry.

To see the complete overview of the series, go to Docker Series page.

The starting point source code for this part can be found on the docker-series-docker-compose-end branch of our docker-series repo on GitHub.

Let’s see what we are going to go learn in this article:

So let’s start off with clearing some concepts up.

Difference Between Docker Repository and Docker Registry

Besides sounding similar these terms can sometimes cause confusion so it seems appropriate to start out by explaining what each one means.

Docker Registry (Docker Trusted Registry – DTR) is an enterprise-grade storage solution for Docker images. In other words, it’s an image storage service. Think about GitHub, but for Docker Images.

We can use one of the existing and well-established cloud registries like Docker Hub, Quay, Google Container Registry, Amazon Elastic Container Registry or any other. We can also make our own registry and host it locally. We’re going to learn how to do that later on in this post.

Docker Repository is a collection of Docker images with the same name and different tags. For example, the repository we’ve used several times so far, microsoft/aspnetcore has a bunch of images with different tags in it. We can choose which one you want to pull by typing docker pull image-name:tag. Something similar to GitHub repo and commits. We can go back to whichever commit we want and pull it to the local machine.

That’s putting it in very simple terms. But now that we cleared the air around these terms we can proceed to the next section.

More About Docker Hub

As we’ve mentioned, Docker Hub is just one of the registry providers. And a good one at that. We can find all sorts of images over there and push our own. We can create unlimited public repositories and one private repo free of charge. If you need more private repositories, you can choose one of the Docker Hub monthly plans.

But that’s not all it does.

Besides providing a centralized resource for image discovery and distribution, Docker Hub’s functionality extends to:

  • Automated builds of images on source code changes and parallel builds
  • Webhooks on image creation and push
  • Groups and organizations management
  • GitHub and BitBucket integration

You can create your own account on Docker Hub right now and try it out.

To push the image from the local machine to Docker Hub we need to type docker login and enter the credentials of your account in the prompt. After that, you can easily push the image by typing docker push accountname/imagename:tag.

Easy as that.

If we don’t specify the tag, Docker will apply the :latest tag to it.

If we want to pull the image from the Docker Hub to the local machine, we need to type docker pull accountname/imagename:tag. The same rule applies here, if you don’t specify the tag, you are going to pull the image tagged :latest.

Let’s move on.

Creating a Local Docker Registry

Docker Hub is super neat and very intuitive and offers a great deal of functionality for free.

But what if we need more privacy? Or our client wants to use its own server.

If that’s the case, we can make our own Docker Registry.

So how do we do that?

Well, we can set up the registry in two different ways:

  • directly with the Docker command
  • using Docker compose

Creating a local registry using docker is pretty straightforward and shouldn’t be such a big deal if you followed the docker series so far. The registry repository is located on the Docker Hub here. (heh, registry repository) Aren’t you glad now that we talked about the differences between these terms 🙂

So if we want to set up the local registry we can type:

Now we can navigate to http://localhost:50000/v2/_catalog and see for yourself that your registry is up and running and that you have no repositories pushed to it.

You should be able to see something like this:

local docker registry empty

If you are wondering how I got the response to look like this in my Chrome, we’re using JSON Viewer Chrome extension. 

The same thing can be done with Docker Compose that we introduced in the previous part of the series.

Let’s navigate to the root of our solution and make a new folder Infrastructure and in it another one called Registry. In the Registry folder, we are going to create a docker-compose.yml file:

We defined the same thing we did with Docker command but with some additional goodies. We added a volume to persist our data, and defined the restart policy as unless-stopped, to keep the registry up unless it is explicitly stopped.

Now we can stop the registry we’ve spin up before with docker stop my-registry and docker rm my-registry to remove the attached container.

After that run docker-compose up -d in the /Infrastructure/Registry folder.

And guess what?

We have the exact same registry we spin up before and we can access it by navigating to http://localhost:50000/v2/_catalog.

We should also add the entry to the windows hosts file so we can use my-registry instead of localhost (usually at C:/Windows/system32/drivers/etc/hosts):

Pushing Images to a Local Docker Registry

Ok, so now we have our own local registry. Let’s push some images to it.

If you’ve followed the series you have the codemazeblog/accountownerapp image on your local machine. If not, please refer to part 4 of the series where you can learn how to create images with Docker Compose.

To push the image to local registry we need to tag it appropriately first:

And then we can push it to the registry:

Now, if we browse to http://localhost:50000/v2/_catalog we will see that our repository list is no longer empty. We successfully added our image to the local registry!

Moreover, if we navigate to http://localhost:50000/v2/codemazeblog/accountownerapp/tags/list we’ll see:

repository tags list

Here we can find the list of all the available tags of our image. Just like we would on Docker Hub when we navigate to tags tab.

To test this out we can remove the local image with docker rmi my-registry:50000/codemazeblog/accountownerapp. Now you can pull the image from the local registry by typing docker pull my-registry:50000/codemazeblog/accountownerapp and behold, once again, the image is on your local machine!

That wasn’t too hard, was it?

There is one important note here. Pushing images to the insecure registries is not recommended and we can easily be the target of the MITM attack if we are not careful.

We’ve talked about HTTP Security and MITM in part 5 of our HTTP Series so if you’re not familiar with it, that’s a good starting point.

Setting a certificate for the registry is beyond the scope of this article and will be described later. For now, you can find more info on how to set a certificate for a local registry here.

So be careful and secure your registries if you want to use them in production.

Let’s wrap this up with some examples of when we might to set up a local Docker registry.

Use Cases for Local Docker Registry

Now that you know pretty much everything you need to run a local registry, you might wonder: “But why should I use a local registry when I have all those nice options available?”.

There are a few reasons for that:

  • Total control of our registry and repositories
  • We need to set up a local network and to easily distribute images throughout it, to save the bandwidth
  • We have a closed network without internet access
  • Setting up a local CI build server that uses that registry
  • We don’t want to pay some crazy plans to cloud providers to host our repositories
  • Many, many others

So there you go.


In this part, we’ve tackled the concepts of Docker registry and repository. We’ve learned what the differences between those two are and learned more about a cloud registry service Docker Hub.

We have also learned how to make our own registry locally and how to push images to it, and pull images from it.

Local registries are neat and have several practical use cases. We gave you some ideas of how you might apply your Docker registry.

Now that we know all this, we can easily transition to the next part where we are going to talk about Continuous Integration with Docker.

The complete source code with the modifications we’ve made in this part can be found on the docker-series-local-registry-end branch of the docker-series repo on GitHub.

If you have enjoyed reading this article and if you would like to receive the notifications about the freshly published Web Development content we encourage you to subscribe to our blog.