由于近期 hub.docker.com 等容器镜像站在国内已经被墙,并且现在看来也无重新可用的可能性了。所以手里有闲置服务器的佬友可以选择自己搭建一个 Docker 镜像加速服务,以便能够中转对 Docker 官方镜像仓库的请求,解决国内无法访问或访问缓慢的问题。本文主要讲述如何使用一台海外 VPS,手动搭建一台镜像加速服务器。
1. 准备工作 2. 获取一个海外 vps 这是使用的是一台Racknerd VPS
配置:3 vCore 2 GB RAM
本教教程使用的操作系统为: Almalinux 8
3. 基础环境安装 3.1. 安装 docker 安装 docker, 请参考博客 - 安装并配置 docker
3.2. 安装防火墙 很多操作系统默认没有安装防火墙,或者防火墙没有开启,建议安装防火墙并开启,毕竟将重要端口暴露在公网会导致服务器被莫名地攻击。
1 2 3 4 sudo dnf install -y firewalldsystemctl enable firewalld --now
4. 部署镜像仓库代理 4.1. 添加 docker-compose.yml 文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 [root@proxy ~]# mkdir -p /data/registry-proxy && cd $_ [root@proxy registry-proxy]# vi docker-compose.yaml services: dockerhub: container_name: reg-docker-hub image: dqzboy/registry:latest restart: always environment: - OTEL_TRACES_EXPORTER=none volumes: - ./registry/data:/var/lib/registry - ./registry-hub.yml:/etc/distribution/config.yml ports: - 51000:5000 networks: - registry-net registry-ui: container_name: registry-ui image: dqzboy/docker-registry-ui:latest environment: - DOCKER_REGISTRY_URL=http://reg-docker-hub:5000 - SECRET_KEY_BASE=9f18244a1e1179fa5aa4a06a335d01b2 - ENABLE_DELETE_IMAGES=true - NO_SSL_VERIFICATION=true restart: always ports: - 50000:8080 networks: - registry-net networks: registry-net:
每个容器挂载对应的 config.yml,这里名称需要与上面 compose.yml 文件定义的挂载的名称保持一致(例如上面挂载的配配置文件名称为 docker-hub.yml);下面只是其中一个示例配置,其他的配置也一样,只需要更改 remoteurl 代理的地址即可! 如果你上面开启了密码认证,那么下面配置中 auth 块的内容需要把注释取消掉!!!
创建 docker-hub 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [root@proxy registry-proxy]# vim docker-hub.yml version: 0.1 log : fields: service: registry storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true cache: blobdescriptor: inmemory blobdescriptorsize: 10000 maintenance: uploadpurging: enabled: true age: 168h interval: 24h dryrun: false readonly : enabled: false http: addr: :5000 headers: X-Content-Type-Options: [nosniff] Access-Control-Allow-Origin: ['*' ] Access-Control-Allow-Methods: ['HEAD' , 'GET' , 'OPTIONS' , 'DELETE' ] Access-Control-Allow-Headers: ['Authorization' , 'Accept' , 'Cache-Control' ] Access-Control-Max-Age: [1728000] Access-Control-Allow-Credentials: [true ] Access-Control-Expose-Headers: ['Docker-Content-Digest' ] health: storagedriver: enabled: true interval: 10s threshold: 3 proxy: remoteurl: https://registry-1.docker.io username: password: ttl: 168h
4.2. 启动容器服务 1 2 3 4 5 6 7 8 9 [root@proxy registry-proxy]# docker compose up -d [root@proxy registry-proxy]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a07955ecac3a dqzboy/docker-registry-ui:latest "/docker-entrypoint.…" 10 minutes ago Up 10 minutes 8443/tcp, 0.0.0.0:50000->8080/tcp, [::]:50000->8080/tcp registry-ui 00a58a54a203 dqzboy/registry:latest "/entrypoint.sh /etc…" 10 minutes ago Up 4 minutes 0.0.0.0:51000->5000/tcp, [::]:51000->5000/tcp reg-docker-hub
防火墙放行 registry-ui 监听端口
1 2 3 4 5 [root@proxy registry-proxy]# firewall-cmd --add-port=50000/tcp --permanent [root@proxy registry-proxy]# firewall-cmd --reload
5. 解析域名 将我们在 Nginx 配置的域名,在 DNS 服务商商进行解析,解析到部署镜像代理仓库的服务器上; 通过访问 UI 地址可以查看镜像仓库缓存的镜像; 通过使用对应的代理域名来下载我们之前无法下载的镜像。 6. 配置 Nginx 反代 6.1. 安装 nginx 1 2 3 4 5 6 7 8 9 sudo dnf install -y nginxsudo firewall-cmd --permanent --zone=public --add-service=httpsudo firewall-cmd --permanent --zone=public --add-service=httpssudo systemctl reload firewalld
6.2. 申请 SSL 证书 首先安装 acme.sh
1 2 3 4 5 6 7 dnf install -y curl socat tar curl https://get.acme.sh | sh source ~/.bashrc
申请 SSL 证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo systemctl stop nginxacme.sh --set-default-ca --server letsencrypt acme.sh --issue --standalone -d hub.example.com --force acme.sh --issue --standalone -d ui.example.com --force sudo systemctl start nginx
安装证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mkdir -p /etc/nginx/certs/sudo systemctl start nginxacme.sh --installcert -d ui.example.com \ --key-file /etc/nginx/certs/ui.example.com.key \ --fullchain-file /etc/nginx/certs/ui.example.com.crt \ --reloadcmd "systemctl restart nginx" --ecc acme.sh --installcert -d hub.example.com \ --key-file /etc/nginx/certs/hub.example.com.key \ --fullchain-file /etc/nginx/certs/hub.example.com.crt \ --reloadcmd "systemctl restart nginx" --ecc
修改 nginx 配置, 为 registry-ui 添加反向代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 [root@proxy registry-proxy]# cd /etc/nginx/conf.d [root@proxy registry-proxy]# vi registry-ui.conf server { listen 80; listen [::]:80; listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name ui.example.com; root /usr/share/nginx/html; http2 on; ssl_certificate "/etc/nginx/certs/ui.example.com.crt" ; ssl_certificate_key "/etc/nginx/certs/ui.example.com.key" ; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; ssl_buffer_size 8k; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; location / { proxy_set_header Host $host ; proxy_set_header Origin $scheme ://$host ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Port $server_port ; proxy_set_header X-Forwarded-Host $host ; proxy_pass http://127.0.0.1:50000; } }
需要将 ui.example.com 替换成你自己的域名
修改 nginx 配置, 为 docker hub 添加反向代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [root@proxy registry-proxy]# cd /etc/nginx/conf.d [root@proxy registry-proxy]# vi docker-hub.conf server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name hub.example.com; root /usr/share/nginx/html; http2 on; ssl_certificate "/etc/nginx/certs/hub.example.com.crt" ; ssl_certificate_key "/etc/nginx/certs/hub.example.com.key" ; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; ssl_buffer_size 8k; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; location / { proxy_set_header Host $host ; proxy_set_header Origin $scheme ://$host ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Port $server_port ; proxy_set_header X-Forwarded-Host $host ; proxy_pass http://127.0.0.1:51000; } }
修改完 nginx 配置后,重启 nginx 服务器
1 2 3 4 5 nginx -t sudo systemctl restart nginx
此时使用 https 的方式访问 registry-ui 了 https://ui.example.com
使用镜像仓库代理 使用自建的 Registry 地址替换官方的 Registry 地址拉取镜像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@proxy registry-proxy]# vi /etc/docker/daemon.json { "registry-mirrors" : [ "https://hub.example.com" ], "live-restore" : true , "debug" : true } [root@proxy registry-proxy]# systemctl daemon-reload [root@proxy registry-proxy]# systemctl restart docker [root@proxy registry-proxy]# docker run hello-world:latest [root@proxy registry-proxy]# docker run hub.example.com/library/hello-world:latest
访问 UI 页面就可以看到上面我们下载的镜像已经被缓存了
配置更多代理 安装以上的方法,我们可以继续配置更多代理
源站 替代 Registry 平台 docker.io hub.example.com docker hub gcr.io gcr.example.com Google Container Registry ghcr.io ghcr.example.com GitHub Container Registry k8s.gcr.io k8s-gcr.example.com Kubernetes Container Registry registry.k8s.io k8s.example.com Kubernetes’s container image registry quay.io quay.example.com Quay Container Registry mcr.microsoft.com mcr.example.com Microsoft Container Registry docker.elastic.co elastic.example.com Elastic Stack nvcr.io nvcr.example.com NVIDIA Container Registry
下面以 gcr 代理为例进行讲解
配置 gcr 镜像加速 首先从 docker-compose.yaml 文件中获取 gcr 容器相关的 docker compose 配置。
将其添加到上文提到的 docker-compose.yml 文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 gcr: container_name: reg-gcr image: dqzboy/registry:latest restart: always environment: - OTEL_TRACES_EXPORTER=none volumes: - ./registry/data:/var/lib/registry - ./registry-gcr.yml:/etc/distribution/config.yml ports: - 53000 :5000 networks: - registry-net
然后在config 目录下对应的 yml 文件到并将其上传到 docker-compose.yml 同级目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 [root@proxy registry-proxy]# vi /data/registry-proxy/registry-gcr.yml version: 0.1 log : accesslog: disabled: true level: info formatter: text fields: service: registry environment: staging storage: cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry maintenance: uploadpurging: enabled: false tag: concurrencylimit: 8 delete: enabled: true http: addr: :5000 headers: X-Content-Type-Options: [nosniff] Access-Control-Allow-Origin: ['*' ] Access-Control-Allow-Methods: ['HEAD' , 'GET' , 'OPTIONS' , 'DELETE' ] Access-Control-Allow-Headers: ['Authorization' , 'Accept' , 'Cache-Control' ] Access-Control-Max-Age: [1728000] Access-Control-Allow-Credentials: [true ] Access-Control-Expose-Headers: ['Docker-Content-Digest' ] health: storagedriver: enabled: true interval: 10s threshold: 3 proxy: remoteurl: https://gcr.io username: password: ttl: 168h [root@proxy registry-proxy]# vi /etc/nginx/conf.d/registry-gcr.conf server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name gcr.example.com; root /usr/share/nginx/html; http2 on; ssl_certificate "/etc/nginx/certs/gcr.example.com.crt" ; ssl_certificate_key "/etc/nginx/certs/gcr.example.com.key" ; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; ssl_buffer_size 8k; proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; location / { proxy_set_header Host $host ; proxy_set_header Origin $scheme ://$host ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Port $server_port ; proxy_set_header X-Forwarded-Host $host ; proxy_pass http://127.0.0.1:53000; } } [root@proxy registry-proxy]# systemctl stop nginx [root@proxy registry-proxy]# acme.sh --issue --standalone -d gcr.example.com --force [root@proxy registry-proxy]# systemctl start nginx [root@proxy registry-proxy]# acme.sh --installcert -d gcr.example.com \ --key-file /etc/nginx/certs/gcr.example.com.key \ --fullchain-file /etc/nginx/certs/gcr.example.com.crt [root@proxy registry-proxy]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@proxy registry-proxy]# systemctl restart nginx
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [root@proxy registry-proxy]# sudo vi /etc/docker/daemon.json { "registry-mirrors" : [ "https://hub.example.com" , "https://gcr.example.com" ], "live-restore" : true , "debug" : true } [root@proxy registry-proxy]# sudo systemctl daemon-reload [root@proxy registry-proxy]# sudo systemctl restart docker [root@proxy registry-proxy]# sudo docker pull google-containers/pause:1.0 [root@proxy registry-proxy]# sudo docker pull gcr.example.com/google-containers/pause:1.0 1.0: Pulling from google-containers/pause a3ed95caeb02: Pull complete 4964c72cd024: Pull complete Digest: sha256:a78c2d6208eff9b672de43f880093100050983047b7b0afe0217d3656e1b0d5f Status: Downloaded newer image for gcr.example.com/google-containers/pause:1.0 gcr.example.com/google-containers/pause:1.0
7. 参考文档 自建 Docker 镜像加速服务:加速与优化镜像管理
Docker-Proxy