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, 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 and application deployment.
- How to Prepare an ASP.NET Core Project for Dockerization
- Why Docker: Docker CLI Through Examples
- Dockerizing ASP.NET Core Application with Dockerfiles
- Adding MySQL to ASP.NET Core App With Docker Compose
- Docker Hub vs Creating a Local Docker Registry (Current article)
- Preparing a Continuous Integration Environment for Docker
- Continuous Integration with TeamCity and Docker
- Continuous Integration with Jenkins and Docker
- Top Docker Monitoring Tools
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 the Docker Series page.
Let’s see what we are going to go learn in this article:
- Difference Between Docker Repository and Docker Registry
- More About Docker Hub
- Creating a Local Docker Registry
- Pushing images to a Local Docker Registry
- Use Cases for Local Docker Registry
So let’s start off with clearing some concepts up.
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.
One docker registry can contain many different docker repositories.
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,
mcr.microsoft.com/dotnet/core/aspnet repository, has many different images in it.
Each image has it’s own tag. For example, for the entire series, we’ve been using the
mcr.microsoft.com/dotnet/core/aspnet:3.1 image which contains ASP.NET Core runtime with version 3.1. We can choose which one we want to pull by typing
docker pull image-name:tag 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.
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
Let’s move on.
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:
docker run -d -p 50000:5000 --restart always --name my-registry registry:latest
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:
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
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
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):
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/accountowner:runtime 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:
docker tag codemazeblog/accountowner:runtime my-registry:50000/codemazeblog/accountowner:runtime
And then we can push it to the registry:
docker push my-registry:50000/codemazeblog/accountowner:runtime
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/accountowner/tags/list we’ll see:
Here we can find the list of all the available tags of our image.
To test this out we can remove the local image with
docker rmi my-registry:50000/codemazeblog/accountowner:runtime. Now you can pull the image from the local registry by typing
docker pull my-registry:50000/codemazeblog/accountowner:runtime 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.
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.
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 the Docker registry and the Docker repository. We’ve learned what the differences between those are and we’ve learned more about a cloud registry service Docker Hub.
We have also learned how to create 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 on 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.