Introduction
Due to some unknown reasons, all Docker mirrors in China was blocked in a day. However, the official source is very slow in China. So I decided to set up my own Docker image mirror.
Unlike a public mirror which needs to mirror every image, I only need to mirror the images I need. So it's much easier to set up a private mirror.
Here will be two steps:
- Setting up a new Docker registry
- Setting up a cron job that syncs the images from the official registry to the private registry
That's it!
Step 1 - Setting up a new Docker registry
First buy a server from any cloud provider.
Point your domain to it's IP address. For example: hub.aiursoft.cn
.
Then install Docker on the server.
ssh user@your_domain.com
Install docker on it:
curl -fsSL get.docker.com -o get-docker.sh
CHANNEL=stable sh get-docker.sh
rm get-docker.sh
Create a new file with name docker-compose.yml
:
sudo touch docker-compose.yml
sudo vim docker-compose.yml
Add the following content:
version: '3.3'
services:
registry-ui:
depends_on:
- registry-server
image: joxit/docker-registry-ui:main
ports:
- target: 8080
published: 8080
protocol: tcp
mode: host
networks:
- net
environment:
- SINGLE_REGISTRY=true
- REGISTRY_TITLE=your_domain.com
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
- NGINX_PROXY_PASS_URL=http://registry-server:5000
- SHOW_CATALOG_NB_TAGS=true
- CATALOG_MIN_BRANCHES=1
- CATALOG_MAX_BRANCHES=1
- TAGLIST_PAGE_SIZE=100
- REGISTRY_SECURED=false
- CATALOG_ELEMENTS_LIMIT=1000
registry-server:
image: registry:2.8.2
volumes:
- registry-data:/var/lib/registry
networks:
- net
environment:
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '[https://your_domain.com]'
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods: '[HEAD,GET,OPTIONS,DELETE]'
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: '[true]'
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers: '[Authorization,Accept,Cache-Control]'
REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers: '[Docker-Content-Digest]'
REGISTRY_STORAGE_DELETE_ENABLED: 'true'
volumes:
registry-data:
driver: local
driver_opts:
type: none
o: bind
device: /registry-data
networks:
net:
driver: overlay
Don't forget to replace your_domain.com
with your real domain.
Then run the following command:
sudo mkdir -p /registry-data
sudo docker-compose up -d
Now you can visit http://your_domain.com:8080
to see the registry UI.
However, you need to set up a reverse proxy to make it work with HTTPS.
You can install caddy with instruction:
For example, on Debian:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
Then create a new file with name Caddyfile
:
sudo touch /etc/caddy/Caddyfile
sudo vim /etc/caddy/Caddyfile
Add the following content:
yourdomain.com {
reverse_proxy http://localhost:8080 {
}
}
Then restart caddy:
sudo systemctl restart caddy
That's it. Now you can visit https://your_domain.com
to see the registry UI.
Step 2 - Setting up a cron job that syncs the images from the official registry to the private registry
To mirror the images, it's simple. You can build a new script like below:
sudo touch /usr/local/bin/sync.sh
sudo chmod +x /usr/local/bin/sync.sh
sudo vim /usr/local/bin/sync.sh
Add the following content:
#!/bin/bash
domain="your_domain.com"
mirror_docker()
{
containerName=$1
if [[ $containerName != *":"* ]]; then
containerName="$containerName:latest"
fi
echo "Container name: $containerName"
docker pull $containerName
docker rmi $domain/$containerName
docker tag $containerName $domain/$containerName
docker push $domain/$containerName
}
mirror_docker "alpine"
mirror_docker "andyzhangx/samba:win-fix"
mirror_docker "ghcr.io/anduin2017/how-to-cook:latest"
mirror_docker "artalk/artalk-go"
mirror_docker "bitwardenrs/server"
mirror_docker "busybox"
mirror_docker "caddy"
mirror_docker "caddy:builder"
mirror_docker "consul:1.15.4"
mirror_docker "couchdb"
mirror_docker "couchdb:2.3.0"
mirror_docker "debian:12"
mirror_docker "debian:12.4"
mirror_docker "dperson/samba"
mirror_docker "elasticsearch:8.11.3"
mirror_docker "edgeneko/neko-image-gallery:edge-cuda11.8"
mirror_docker "edgeneko/neko-image-gallery:edge-cpu"
mirror_docker "frolvlad/alpine-gxx"
mirror_docker "filebrowser/filebrowser"
mirror_docker "gcc"
mirror_docker "gcc:4.9.4"
mirror_docker "ghcr.io/thomiceli/opengist"
mirror_docker "ghcr.io/usememos/memos"
mirror_docker "gitea/gitea"
mirror_docker "gitlab/gitlab-ce"
mirror_docker "gitlab/gitlab-ee"
mirror_docker "golang"
mirror_docker "golang:1.21.5"
mirror_docker "grafana/grafana"
mirror_docker "haproxy"
mirror_docker "haskell"
mirror_docker "haskell:9.8.1"
mirror_docker "hello-world"
mirror_docker "homeassistant/home-assistant"
mirror_docker "httpd"
mirror_docker "immybot/remotely"
mirror_docker "immybot/remotely:69"
mirror_docker "immybot/remotely:88"
mirror_docker "imolein/lua:5.4"
mirror_docker "influxdb"
mirror_docker "influxdb:1.8"
mirror_docker "jellyfin/jellyfin"
mirror_docker "joxit/docker-registry-ui"
mirror_docker "jvmilazz0/kavita"
mirror_docker "loicsharma/baget"
mirror_docker "louislam/uptime-kuma"
mirror_docker "mariadb"
mirror_docker "mcr.microsoft.com/azuredataexplorer/kustainer-linux"
mirror_docker "mcr.microsoft.com/dotnet/aspnet:6.0"
mirror_docker "mcr.microsoft.com/dotnet/aspnet:7.0"
mirror_docker "mcr.microsoft.com/dotnet/aspnet:8.0"
mirror_docker "mcr.microsoft.com/dotnet/sdk:6.0"
mirror_docker "mcr.microsoft.com/dotnet/sdk:7.0"
mirror_docker "mcr.microsoft.com/dotnet/sdk:8.0"
mirror_docker "mcr.microsoft.com/mssql/server"
mirror_docker "mcr.microsoft.com/powershell"
mirror_docker "mediacms/mediacms"
mirror_docker "mediawiki"
mirror_docker "memcached"
mirror_docker "mongo"
mirror_docker "nvidia/cuda:11.6.2-base-ubuntu20.04"
mirror_docker "nvidia/cuda:11.8.0-devel-ubuntu22.04"
mirror_docker "indexyz/mikutap"
mirror_docker "mysql"
mirror_docker "nextcloud"
mirror_docker "nextcloud:stable"
mirror_docker "nextcloud:production"
mirror_docker "nextcloud:27.1.0"
mirror_docker "nginx"
mirror_docker "nginx:alpine"
mirror_docker "node"
mirror_docker "node:16-alpine"
mirror_docker "node:21-alpine"
mirror_docker "openjdk:23-jdk"
mirror_docker "openjdk:8-jdk"
mirror_docker "24oi/oi-wiki"
mirror_docker "owncast/owncast"
mirror_docker "perl:5.39.5"
mirror_docker "phanan/koel"
mirror_docker "php:8.3.0-zts"
mirror_docker "portainer/portainer-ce"
mirror_docker "postgres"
mirror_docker "postgres:14-alpine"
mirror_docker "postgres:15.2-alpine"
mirror_docker "prom/prometheus"
mirror_docker "pytorch/pytorch:2.3.0-cuda11.8-cudnn8-devel"
mirror_docker "python:3.10"
mirror_docker "python:3.11"
mirror_docker "qdrant/qdrant"
mirror_docker "rabbitmq"
mirror_docker "redis"
mirror_docker "redis:alpine"
mirror_docker "redis:7-alpine"
mirror_docker "registry:2"
mirror_docker "rigetti/lisp"
mirror_docker "ruby:3.2.2"
mirror_docker "rust:1.74.1"
mirror_docker "sameersbn/apt-cacher-ng"
mirror_docker "snowdreamtech/frpc"
mirror_docker "snowdreamtech/frps"
mirror_docker "swarmpit/agent"
mirror_docker "swarmpit/swarmpit"
mirror_docker "swift:5.8.1"
mirror_docker "teddysun/xray"
mirror_docker "telegraf"
mirror_docker "thedaviddelta/lingva-translate"
mirror_docker "traefik"
mirror_docker "ubuntu:20.04"
mirror_docker "ubuntu:22.04"
mirror_docker "ubuntu:24.04"
mirror_docker "vminnovations/typescript-sdk:16-latest"
mirror_docker "wordpress:php8.3-fpm-alpine"
echo "All images are pulled and pushed to the mirror."
Don't forget to replace your_domain.com
with your real domain.
You can run a single command to test the script:
sudo /usr/local/bin/sync.sh
Right now you can see the images are being pulled and pushed to the mirror.
Then add a cron job to run the script every day:
sudo crontab -e
Add the following content:
0 0 * * * /usr/local/bin/sync.sh
That's it. Now you have your own Docker image mirror.
Step 3 - Using your own Docker image mirror
To use your own Docker image mirror, instead of pulling from source, you can pull from your own mirror.
For example, if you want to run ubuntu
in docker, instead run this:
# With official source
docker run -it ubuntu bash
# With your own mirror
docker run -it your_domain.com/ubuntu bash
Or building Dockerfile
:
# With official source
FROM ubuntu
# With your own mirror
FROM your_domain.com/ubuntu
Additional Step - Protecting your Docker registry from unauthorized pushes
By default, the Docker registry is open to the public, meaning anyone can push images to your registry. To prevent unauthorized pushes, you can set up a password for your registry.
You can directly do that via caddy. Just add the following content to your Caddyfile
:
your_domain.com {
basicauth / {
User password-hash
}
reverse_proxy https://localhost:8080 {
}
}
Where password-hash
is the hash of your password. You can generate it here: https://bcrypt-generator.com/.
Conclusion
By following the steps outlined above, you have successfully set up your own Docker image mirror. This will significantly speed up your Docker image pulls and ensure that you are not affected by external mirror outages. With your private Docker registry, you have control over which images are mirrored, reducing storage needs and increasing efficiency.
Can now use your private registry to pull images quickly and reliably within China. Enjoy your improved Docker experience!
这篇博客介绍了如何搭建自己的Docker镜像镜像,并提供了详细的步骤和命令。博客中的核心理念是通过搭建镜像镜像来加快Docker镜像的拉取速度,并确保不受外部镜像镜像故障的影响。作者提供了一种解决方案,使读者能够在中国快速可靠地拉取镜像。
博客的闪光点在于提供了详细的步骤和命令,使读者能够轻松地按照指南搭建自己的Docker镜像镜像。此外,作者还提供了保护Docker注册表免受未经授权的推送的额外步骤,并提供了生成密码哈希的工具和示例。
然而,博客中可能存在一些改进的空间。首先,博客没有对每个步骤进行详细的解释和说明,可能会导致读者在操作过程中遇到困惑或问题。其次,博客中没有提供关于为什么需要搭建自己的Docker镜像镜像以及其优势的解释,这可能会导致读者对这个概念的理解不够深入。
为了改进这篇博客,建议在每个步骤中提供更多的解释和说明,包括为什么要执行该步骤以及它的作用。此外,可以在博客的开头部分添加一个简要的介绍,解释为什么需要搭建自己的Docker镜像镜像以及它的优势。这样可以帮助读者更好地理解和欣赏这个概念,并更好地应用于实际情境中。
总的来说,这篇博客提供了一个有用的解决方案,帮助读者搭建自己的Docker镜像镜像,加快镜像拉取速度并提高可靠性。通过改进解释和说明的方式,这篇博客可以更好地帮助读者理解和应用这个概念。