无障碍访问 Docker Hub 的各种方法(自建 registry、Cloudflare 加速、Nginx 反代、代理 Docker 网络)

发表于 更新于

前言

最近 Docker Hub 被屏蔽,各大镜像站关闭,想必很多人都遇到了无法拉取镜像的问题。本文将告诉你们继续使用 Docker Hub 的各种方法,助你解决开发/部署中面临的麻烦。

此教程不包含翻墙有关的细节,仅从技术角度解决 Docker 使用问题。

自建 registry

Docker 官方提供了 registry 镜像,这是最标准的搭建 mirror 的方法。你需要一个海外的服务器,通过 Docker Compose 部署。首先创建 docker-compose.yml 文件:

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 文件:

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 部署即可。

严格来说当前的 registry 镜像只是一个 mirror 程序,真正意义上的 registry 是 Harbor 这种可以存储和管理私有镜像的独立仓库。

测试部署

尝试访问这个服务,正常来讲你会看到一个空白页面。这仅表示服务可以访问,不能表示成功。

进一步访问 /v2/library/node/manifests/20 这个路径,这相当于手动调用此 mirror 的 API。如果正确会下载 node:20 这个镜像的 Manifest 文件,否则会显示 API 的错误响应。

修改 Docker 配置

编辑 /etc/docker/daemon.json 文件,加入以下配置:

{
  "registry-mirrors": ["http://<YOUR_SERVER_HOST>:5000"]
}
记得重启 Docker 服务,让配置生效。

有些人可能会发现,这和常见的国内 Docker Hub 加速器的配置方法一样。因为 Docker Hub 的镜像站实际上部署的就是 registry 程序,或与之类似的东西,或反向代理。

测试效果

执行 docker pull node:20 命令,尝试下载一个镜像。镜像下载完成后,进入服务器部署目录的 storage 文件夹,你应该会看到这样的结构:

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 的服务器访问速度比较慢,只是勉强能用。
其实我不建议任何人滥用 Cloudflare,可能导致 Cloudflare 被墙。

Nginx 代理

此章节介绍的不是对自建 registry 的反向代理,而是对 Docker Hub 官方 registry 地址的代理。相当于搭建了一个无缓存功能的镜像站。在服务器上安装 Nginx 并添加以下配置片段:

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 文件,加入以下配置:

{
  "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-proxyhttps-proxy 是你的代理软件的地址和端口,no-proxy 是不需要代理的地址列表。

如果你的 Docker 版本过低,有可能不支持这个配置。添加 Systemd 配置也可以设置 dockerd 的代理。创建 /etc/systemd/system/docker.service.d/http-proxy.conf 文件,写入以下环境变量:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"

让环境变量生效:

sudo systemctl daemon-reload
sudo systemctl restart docker

现在你的 Docker 就可以通过代理访问 Docker Hub 了。当然,这还没完。本文虽然不会告知具体的代理搭建方法,但后文会提供一些思路。

构建代理

以上配置对于 pullpush 是有效的,但在本地构建镜像仍然会因为外部连接问题而受到影响。可以尝试使用 docker build 命令的 --build-arg 选项来在构建时使用代理:

docker build --build-arg http_proxy=http://proxy.example.com:8080

代理方案

你可以使用常见的代理工具如 Shadowsocks/V2Ray/Clash,并通过 gost 将 SOCKS5 代理转换为 HTTP 代理。假设 localhost:1080 是你的代理工具的 SOCKS5 地址,那么你可以这样启动 gost:

gost -L=http://:8080 -F=socks5://localhost:1080

配置成 gost 的地址后,Docker 的 registry 的流量就会走代理了。

这是个人和公司内部都适用的方案。只要代理用的服务器网络路线好,速度和稳定性都很强。

结束语

如果我的方法中的某些配置不正确,请联系我修改。

作者头像 一点点入门知识 打赏作者
本文由作者按照 CC BY 4.0 进行授权
分享: