The Docker Registry is an open source option if you want to totally go at it on your own. If you totally want hands off, you can always use the Docker Hub and rely on public and private repositories, which will run you a fee on the Docker Hub though. This can be hosted locally on a server of your choosing or on a cloud service.
The installation of the Docker Registry is extremely simply as it runs in a Docker container. This allows you to run it virtually anywhere, on a virtual machine in your own server environment or in a cloud environment. The typical port that is used is port 5000
, but you can change it to suit your needs:
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2.2
One of the other items you will notice from above is that we are specifying a version to use instead of leaving it blank and pulling the latest version. That is because as of writing this book, the latest version for that registry tag is still at version 0.9.1. Now, while this might be suitable for some, version 2 is stable enough to be considered and to run your production environment on. We are also introducing the --restart=always
flag for that as in the event of something happening to the container, it will restart and be available to serve out or accept images.
Once you have run the command above, you will have a running container registry on the IP address of the Docker host you ran the command on along with the port selection that you used in your docker run
command above.
Now it is time to put some images up on your new registry. The first thing we need is an image to push to the registry and we can do that in two ways. We can build images based on Docker files that we have created or we can pull down an image from another registry, in our case we will be using the Docker Hub, and then push that image to our new registry server. First, we need an image to choose and again, we will default back to the mysql
image since it's a more popular image that most people might be using in their environments at some point along the way.
$ docker pull mysql Using default tag: latest latest: Pulling from library/mysql 1565e86129b8: Pull complete a604b236bcde: Pull complete 2a1fefc8d587: Pull complete f9519f46a2bf: Pull complete b03fa53728a0: Pull complete ac2f3cdeb1c6: Pull complete b61ef27b0115: Pull complete 9ff29f750be3: Pull complete ece4ebeae179: Pull complete 95255626f143: Pull complete 0c7947afc43f: Pull complete b3a598670425: Pull complete e287fa347325: Pull complete 40f595e5339f: Pull complete 0ab12a4dd3c8: Pull complete 89fa423a616b: Pull complete Digest: sha256:72e383e001789562e943bee14728e3a93f2c3823182d14e3e01b3fd877976265 Status: Downloaded newer image for mysql:latest
Next, you need to tag the image so it will now be pointing to your new registry so you can do push it to the new location:
$ docker tag mysql <IP_address>:5000/mysql
Let's break down that command above. What we are doing is applying the tag of <IP_address>:5000/mysql
to the mysql
image that we pulled from the Docker Hub. Now that <IP_address>
piece will be replaced by the IP address from the Docker host that is running the registry container. This could also be a DNS name as well, as long as the DNS points to the correct IP that is running on the Docker host. We also need to specify the port number for our registry server, and in our case we left it with port 5000
, so we include: 5000
in the tag. Then, we are going to give it the same same of mysql
at the end of the command. We are now ready to push this image to our new registry.
$ docker push <IP_address>:5000/mysql
After it has been pushed, you can now pull it down from another machine that is configured with Docker and has access to the registry server.
$ docker pull <IP_address>:5000/mysql
What we have looked at here are the defaults and while it could work if you want to use firewalls and such to secure the environment or even internal IP address, you still might want to take security to the next level and that is what we will look at in the next section. How can we make this even more secure?
It's time to tighten up our running registry with some additional features. The first method would be to run your registry using TLS. Using TLS allows you to apply certificates to the system so that people who are pulling from it know that it is who you say it is by knowing that someone hasn't comprised the server or is doing a man in the middle attack by supplying you with compromised images.
To do that, we will need to rework the Docker run
command we were running in the last section. This is going to assume you have gone through some of the process of obtaining a certificate and key from your enterprise environment or you have self signed one using another piece of software.
Our new command will look like this:
$ docker run -d -p 5000:5000 --restart=always --name registry -e REGISTRY_HTTP_TLS_CERTIFICATE=server.crt -e REGISTRY_HTTP_TLS_KEY=server.key -v <certificate folder>/<path_on_container> registry:2.2.0
You will need to be in the directory where the certificates are or specify the full path to them in the above command. Again, we are keeping the standard port of 5000
, along with the name of registry. You could alter that too to something that might suit you better. For the sake of this book we will keep it close to that in the official documentation in the event that you look there for more reference. Next, we add two additional lines to the run
command:
-e REGISTRY_HTTP_TLS_CERTIFICATE=server.crt -e REGISTRY_HTTP_TLS_KEY=server.key
This will allow you to specify the certificate and key file that you will be using. These two files will need to be in the same directory that you are running the run command from as the environmental variables will be looking for them upon run. Now you could also add a volume switch to the run command to make it a little cleaner if you like and put the certificate and key in that folder and run the registry server that way.
The other way you can help with security is by putting a username and password on the registry server. This will help when users want to push or pull an item as they will need the username and password information. The catch with this is that you have to be using TLS in conjunction with this method. This method of username and password is not a standalone option.
First, you need to create a password file that you will be using in your run
command:
$ docker run --entrypoint htpasswd registry:2.2.0 -bn <username> <password> > htpasswd
Now, it can be a little confusing to understand what is happening here, so let's clear that up before we jump to the run
command. First, we are issuing a run
command. This command is going to run the registry:2.2.0
container and its entry point specified means to run the htpasswd
command along with the -bn
switches, which will inject the username
and password
in an encrypted fashion into a file called htpasswd
that you will be using for authentication purposes on the registry server. The -b
means to run in batch mode while the -n
means to display the results, and the >
means to put those items into a file instead of to the actual output screen.
Now, onto our newly enhanced and totally secure Docker run
command for our registry:
$ docker run -d -p 5000:5000 --restart=always --name registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Name" -e REGISTRY_AUTH_HTPASSWD_PATH=htpasswd -e REGISTRY_HTTP_TLS_CERTIFICATE=server.crt -e REGISTRY_HTTP_TLS_KEY=server.key registry:2.20
Again, it's a lot to digest but let's walk through it. We have seen some of these lines before in:
-e REGISTRY_HTTP_TLS_CERTIFICATE=server.crt -e REGISTRY_HTTP_TLS_KEY=server.key
The new ones are:
-e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Name" -e REGISTRY_AUTH_HTPASSWD_PATH=htpasswd
The first one tells the registry server to use htpasswd
as its authentication method to verify clients. The second gives your registry a name and can be changed at your own discretion. The last one tells the registry server the location of the file that is to be used for the htpasswd
authentication. Again, you will need to use volumes and put the htpasswd
file in its own volume inside the container so it allows for easier updating down the road. You also need to remember the htpasswd
file needs to be placed in the same directory as the certificate and key file when you execute the Docker run
command.