Building a Mirror Docker Registry
Sometimes when browsing Docker.io, I come across popular projects that I would like to experiment with. However, I often find that these projects have been deleted. This prompted me to think about setting up a mirror docker registry, so that I can directly store interesting projects in my own registry for future use.
TOC
- Setting up a Docker.io Mirror Registry
- Client Operations in a Linux Environment
- Setting up a Microsoft Artifact Registry
- Client Operations in a Windows Environment
- Setting up an Azure Container Registry
- Client Operations in a Mac OS Environment
- Handling Routing Issues
- Managing the Docker Registry
Setting up a Docker.io Mirror Registry
I use Ubuntu Server 22.04 as the Mirror Registry. Since a docker registry is also a docker container, you need to first install the Docker daemon on your server. Please refer to these two documents for installation instructions.
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-22-04
Next, create a directory to store the actual mirror stuff. Please note that a Docker Registry can only mirror services under a single domain. Let’s take docker.io as an example.
cd ~/
mkdir -p dr-docker-5000/data
Create a configuration yml file.
vi dr-docker-5000/docker-compose.yml
version: '3'
services:
registry:
restart: always
image: registry:latest
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
volumes:
- ./data:/data
Launch this container.
cd ~/dr-docker-5000/
docker compose up -d
And that’s it, we have completed the setup. Now let’s take a look at how to use it.
Client Operations in a Linux Environment
The most common Docker projects are usually built in a Linux environment. Therefore, let’s start by simulating the operations of the end user in a Linux environment.
I use Ubuntu Server 22.04 as the end user client part. First, you need to create the file /etc/docker/daemon.json with root privileges. Please be noticed that “10.10.10.19” is the LAN IP from the mirror docker registry.
vi /etc/docker/daemon.json
{
"insecure-registries": [
"10.10.10.19:5000"
],
"registry-mirrors": [
"http://10.10.10.19:5000"
]
}
Then, edit the Docker service configuration file /usr/lib/systemd/system/docker.service and append “–config-file /etc/docker/daemon.json” at the end of the “ExecStart” line.
vi /usr/lib/systemd/system/docker.service
Once you have made the changes, save the file and restart the Docker service.
systemctl daemon-reload
systemctl restart docker
Now we can start pulling the project from docker.io.
docker pull 10.10.10.19:5000/library/hello-world:latest
The endpoint mentioned above is divided into three parts. The “10.10.10.19:5000” represents that we are accessing it through the mirrored Docker registry. “library” is a fixed route reserved by Docker.io, and we will explain it in detail in the following chapters. Finally, “hello-world:latest” is the project name and tag that you see on Docker.
Previously, the pull syntax only included “hello-world:latest”, but now it should be “10.10.10.19:5000/library/hello-world:latest”.
Setting up a Microsoft Artifact Registry
Let’s take Microsoft Artifact Registry as an example. Now, there are also increasing numbers of Docker projects that belong to the Windows operating system. Windows projects tend to be larger in size, and having a mirror registry eliminates the need to spend a lot of time pulling images every time.
cd ~/
mkdir -p dr-mcr-5001/data
Create a configuration yml file.
vi dr-mcr-5001/docker-compose.yml
version: '3'
services:
registry:
restart: always
image: registry:latest
ports:
- "5001:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
REGISTRY_PROXY_REMOTEURL: https://mcr.microsoft.com
volumes:
- ./data:/data
Launch this container.
cd ~/dr-mcr-5001/
docker compose up -d
And that’s it.
Client Operations in a Windows Environment
To use Docker images in a Windows environment, you need to have Docker Desktop installed with the Windows Docker daemon. Therefore, let’s simulate the operations of an end user in a Windows 11 environment.
First, open Docker Desktop, then click on the gear icon (Settings) in the upper right corner. Select “Docker Engine” on the left side. In the appropriate section, add the following content. Finally, click on “Apply & Restart” to save the changes and restart Docker.
"insecure-registries": [
"10.10.10.19:5001"
],
"registry-mirrors": [
"http://10.10.10.19:5001"
]
Now we can start pulling the project from Microsoft Artifact Registry.
docker pull 10.10.10.19:5001/windows/nanoserver:ltsc2022
Setting up an Azure Container Registry
Let’s take Azure Container Registry as an example of a private registry. It can be used to mirror images that require login authorization. This time, let’s simulate the operations of an end user in a Mac OS environment.
cd ~/
mkdir -p dr-cchlabacr-5002/data
Create a configuration yml file.
vi dr-cchlabacr-5002/docker-compose.yml
version: '3'
services:
registry:
restart: always
image: registry:latest
ports:
- "5002:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
REGISTRY_PROXY_REMOTEURL: https://<your-acr-name>.azurecr.io
REGISTRY_PROXY_USERNAME: <your-acr-user>
REGISTRY_PROXY_PASSWORD: <your-acr-pass>
volumes:
- ./data:/data
Which the information from <your-acr-name> and <your-acr-user> and <your-acr-pass> could be located here:
Launch this container.
cd ~/dr-cchlabacr-5002/
docker compose up -d
And that’s it.
Client Operations in a Mac OS Environment
We will use Mac OS X as the operating system. First, open Docker Desktop, then click on the gear icon (Settings) in the upper right corner. Select “Docker Engine” on the left side. In the appropriate section, add the following content. Finally, click on “Apply & Restart” to save the changes and restart Docker.
"insecure-registries": [
"10.10.10.19:5002"
],
"registry-mirrors": [
"http://10.10.10.19:5002"
]
Now we can start pulling the project from Azure Container Registry.
docker pull 10.10.10.19:5002/hello-world:latest
Handling Routing Issues
Look into these commands:
docker pull 10.10.10.19:5000/library/hello-world:latest
docker pull 10.10.10.19:5001/windows/nanoserver:ltsc2022
docker pull 10.10.10.19:5002/hello-world:latest
The original command without using mirror registry should be like:
docker pull hello-world:latest
docker pull mcr.microsoft.com/windows/nanoserver:ltsc2022
docker pull
Command 1: Docker is a product of Docker.io, so by default it searches the website https://registry-1.docker.io. You don’t need to explicitly mention it. The reason we have the route named “library” is because different registry implementations in different companies have different routing methods. “library” is a standard that many people use, so if you need to use a proxy server to assist with the requests, you need to add it.
Command 2: From experimentation, using both “10.10.10.19:5001/library/windows/nanoserver:ltsc2022” and “10.10.10.19:5001/windows/nanoserver:ltsc2022” works. Therefore, if you encounter a “manifest unknown” error in the future, you can try both options.
Command 3: From experimentation, it has been found that Azure Container Registry (ACR) does not support the commonly used “library” route. Therefore, when making requests, you should exclude the “library” route.
Managing the Docker Registry
When the number of mirrored projects increases, it becomes necessary to manage them in GUI mode. Fortunately, there are mature solutions available for this requirement. Let’s go back to the mirrored server from the beginning and proceed with the installation process.
cd ~/
mkdir dr-ui-4999
vi dr-ui-4999/docker-compose.yml
version: '3'
services:
registry-ui:
restart: always
image: joxit/docker-registry-ui:latest
ports:
- "4999:80"
environment:
SINGLE_REGISTRY: false
CATALOG_ELEMENTS_LIMIT: 1000
cd ~/dr-ui-4999/
docker compose up -d
To avoid CORS (Cross-Origin Resource Sharing) issues, the original three registries need additional configuration settings.
# Step 1 (choose one of them)
docker exec -it dr-docker-5000-registry-1 /bin/sh
docker exec -it dr-mcr-5001-registry-1 /bin/sh
docker exec -it dr-cchlabacr-5002-registry-1 /bin/sh
# Step 2
vi /etc/docker/registry/config.yml
vi /etc/docker/registry/config.yml
# Rewrite the http section like this
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Origin: ['*']
Access-Control-Allow-Methods: ['*']
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Max-Age: [1728000]
Access-Control-Allow-Credentials: [true]
Access-Control-Expose-Headers: ['Docker-Content-Digest']
And that’s it. We could now accessing the management page via http://10.10.10.19:4999