无障碍访问 Docker Hub 的各种方法总结(自建 registry、Cloudflare 加速、Nginx 反代、代理 Docker 网络)
最近 Docker Hub 被屏蔽,各大镜像站关闭,想必很多人都遇到了无法拉取镜像的问题。本文将告诉你们继续使用 Docker Hub 的各种方法,助你解决开发/部署中面临的麻烦。
自建 registry
Docker 官方提供了 registry 镜像,这是最标准的搭建 mirror 的方法。你需要一个海外的服务器,通过 Docker Compose 部署。首先创建 docker-compose.yml 文件:
XML/HTML代码
- services:
- server:
- image: registry
- restart: always
- ports:
- - 5000:5000
- volumes:
- - ./config.yml:/etc/docker/registry/config.yml
- - ./storage:/var/lib/registry
假定放在服务器的 docker/registry 目录。先不要部署,我们还需要在此目录创建 config.yml 文件:
XML/HTML代码
- version: 0.1
- proxy:
- remoteurl: https://registry-1.docker.io
- log:
- level: debug # <- 如果部署后测试没问题,请改为 info
- http:
- addr: 0.0.0.0:5000
- cache:
- blobdescriptor: inmemory
- storage:
- filesystem:
- rootdirectory: /var/lib/registry
现在执行 docker compose up -d 部署即可。
XML/HTML代码
- docker run --name docker-proxy --restart always -p 5000:5000 -v ./config.yml:/etc/docker/registry/config.yml -v ./storage:/var/lib/registry registry
严格来说当前的 registry 镜像只是一个 mirror 程序,真正意义上的 registry 是 Harbor 这种可以存储和管理私有镜像的独立仓库。
测试部署
尝试访问这个服务,正常来讲你会看到一个空白页面。这仅表示服务可以访问,不能表示成功。
进一步访问 /v2/library/node/manifests/20 这个路径,这相当于手动调用此 mirror 的 API。如果正确会下载 node:20 这个镜像的 Manifest 文件,否则会显示 API 的错误响应。
修改 Docker 配置
编辑 /etc/docker/daemon.json 文件,加入以下配置:
XML/HTML代码
- {
- "registry-mirrors": ["http://<YOUR_SERVER_HOST>:5000"]
- }
记得重启 Docker 服务,让配置生效。
有些人可能会发现,这和常见的国内 Docker Hub 加速器的配置方法一样。因为 Docker Hub 的镜像站实际上部署的就是 registry 程序,或与之类似的东西,或反向代理。
测试效果
执行 docker pull node:20 命令,尝试下载一个镜像。镜像下载完成后,进入服务器部署目录的 storage 文件夹,你应该会看到这样的结构:
XML/HTML代码
- storage/
- ├── docker
- │ └── registry
- │ └── v2
- │ ├── blobs
- │ │ └── sha256
- │ │ ├── 0e
- │ │ ├── 18
- │ │ ├── 48
- │ │ ├── 51
- │ │ ├── 7e
- │ │ ├── 86
- │ │ ├── ae
- │ │ ├── c9
- │ │ ├── ca
- │ │ ├── ee
- │ │ ├── f7
- │ │ └── ff
- │ └── repositories
- │ └── library
- │ └── node
- └── scheduler-state.json
这表示服务器正确的缓存了镜像的信息和 blobs 到本地,下次拉取同一个镜像服务器就不会再走 Docker Hub 了。
registry 程序的配置内容还有很多,此处仅提供一个最简化的配置。更多请参考这里。
Cloudflare Workers 代理
如果你没有服务器,你还可以利用 Cloudflare 来代理。Workers 是 Cloudflare 提供的 Serverless(无服务器)方案,实际上部署到 Workers 的程序会在 Cloudflare 自己的服务器上运行。你需要一个域名,且被 Cloudflare 托管。
我们编写一个将 Workers 的访问请求代理到 registry 的简单程序,就相当于把 Cloudflare 服务器做成反向代理了。已经有人写好了这样的程序,仓库地址:ciiiii/cloudflare-docker-proxy。访问此 Workers 应用的部署链接,按步骤分别连接上 GitHub 和 Cloudflare,它将自动为你 fork 仓库、启用 Actions 并部署到 Workers。
默认情况下部署会失败,你需要修改配置的域名。克隆 fork 后的仓库到本地,用编辑器批量替换 libcuda.so 为你自己的域名。最后提交修改触发 GitHub Actions,部署成功后 Workers 就能直接使用了。
测试 Workers
首先访问你的 Workers 中配置的域名,例如 docker.your.domain,如果得到的响应和访问 https://registry-1.docker.io 一模一样,就表示代理成功了。接下来,按照修改 Docker 配置章节设置 registry-mirrors 即可。
这个 Workers 程序还包含了对 K8S、ghcr 等的代理配置,默认会一并部署上。具体可以自行查阅仓库说明以及代码(非常简单,只是请求的代理而已)。
此方案建议用于个人,因为免费的 Workers 请求次数/流量有限,不适合公司内部大规模使用。并且 Cloudflare 的服务器访问速度比较慢,只是勉强能用。
Nginx 代理
此章节介绍的不是对自建 registry 的反向代理,而是对 Docker Hub 官方 registry 地址的代理。相当于搭建了一个无缓存功能的镜像站。在服务器上安装 Nginx 并添加以下配置片段:
XML/HTML代码
- location / {
- client_max_body_size 1024M;
- proxy_pass https://registry-1.docker.io:443;
- proxy_set_header Authorization $http_authorization;
- proxy_pass_header Authorization;
- proxy_redirect https://registry-1.docker.io $scheme://$http_host;
- }
以上配置将客户端上传的数据限制在 1GB,如有特殊需求请自行修改。
访问此 location 对应的地址,如果得到的响应和访问 https://registry-1.docker.io 一模一样,就表示代理成功了。接下来,按照修改 Docker 配置章节设置 registry-mirrors 即可。
此方案简单有效,可用性也非常高。
本地代理
通过代理本地网络访问被屏蔽的服务是最为通用的方式,可以作为后备之选。
配置文件
Docker 自带一个配置后台进程 dockerd 的文件,它包含代理的配置选项。编辑 /etc/docker/daemon.json 文件,加入以下配置:
XML/HTML代码
- {
- "proxies": {
- "http-proxy": "http://proxy.example.com:8080",
- "https-proxy": "https://proxy.example.com:8083",
- "no-proxy": "*.test.example.com,.example.org,127.0.0.0/8"
- }
- }
如果你是 Windows,路径在 C:\ProgramData\docker\config\daemon.json。
这里的 http-proxy 和 https-proxy 是你的代理软件的地址和端口,no-proxy 是不需要代理的地址列表。
如果你的 Docker 版本过低,有可能不支持这个配置。添加 Systemd 配置也可以设置 dockerd 的代理。创建 /etc/systemd/system/docker.service.d/http-proxy.conf 文件,写入以下环境变量:
XML/HTML代码
- [Service]
- Environment="HTTP_PROXY=http://proxy.example.com:8080"
让环境变量生效:
XML/HTML代码
- sudo systemctl daemon-reload
- sudo systemctl restart docker
现在你的 Docker 就可以通过代理访问 Docker Hub 了。当然,这还没完。本文虽然不会告知具体的代理搭建方法,但后文会提供一些思路。
构建代理
以上配置对于 pull 和 push 是有效的,但在本地构建镜像仍然会因为外部连接问题而受到影响。可以尝试使用 docker build 命令的 --build-arg 选项来在构建时使用代理:
XML/HTML代码
- docker build --build-arg http_proxy=http://proxy.example.com:8080
代理方案
你可以使用常见的代理工具如 Shadowsocks/V2Ray/Clash,并通过 gost 将 SOCKS5 代理转换为 HTTP 代理。假设 localhost:1080 是你的代理工具的 SOCKS5 地址,那么你可以这样启动 gost:
XML/HTML代码
- gost -L=http://:8080 -F=socks5://localhost:1080
配置成 gost 的地址后,Docker 访问 registry 的流量就会走代理了。
这是个人和公司内部都适用的方案。只要代理用的服务器网络路线好,速度和稳定性都很强。