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.
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.
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.
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:
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
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/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:
docker tag codemazeblog/accountownerapp:latest my-registry:50000/codemazeblog/accountownerapp:latest
And then we can push it to the registry:
docker push my-registry:50000/codemazeblog/accountownerapp
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:
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.
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 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.