利用 harbor + nginx 搭建带缓存的 docker mirror

Harbor 可以直接配置作为 Docker Mirror,但是这样的话整个 Harbor 就只能作为 mirror 使用了不能再作为自定义的镜像仓库,同时也失去了很多的配置能力

本文利用 Harbor 的 Proxy Cache 功能搭配 nginx 转发来实现让 harbor 可以充当内部镜像服务器的同时也可以作为 docker mirror 使用。

配置 Harbor 镜像

定义 Harbor Registry

进入 Administration → Registries,创建 Endpoint

image-20240725-082311.png

如果你的 Harbor 可以直连 Docker Hub,在 Provider 选择 Docker Hub 即可,如果你的用量较大也可以设置 Access ID 和 Access Secret(Access ID 就是你的用户名,Access Secret 就是你设置的 Access Token;不设置每 6h 可以 pull 100 次,设置了可以 200 次,具体参见 https://docs.docker.com/docker-hub/download-rate-limit/

image-20240725-082247.png

如果你的 Harbor 无法直连 Docker Hub,则需要使用一个中转(例如利用 https://github.com/ImSingee/hammal 自建,或者在网上找其他可以使用的镜像服务)

中转搭建或选择好后,创建 Endpoint 时 Provider 选择 Docker Registry,然后在 Endpoint URL 处输入你的中转站点的网址

创建一个 harbor project

进入 Harbor 的 Projects 页面,创建一个新的 harbor project(假设命名为 docker-mirror),勾选 proxy cache 并选择上面创建好的 Registry Endpoint

创建好后,可以进入 Configuration 进一步配置保留策略,来防止长期不用的镜像占用空间

利用 nginx 模拟 docker mirror

按照上述创建好 harbor 以后,已经可以利用类似 docker pull harbor.example.com/docker-mirror/library/alpine 这样的方式来读取到缓存的 dockerhub 包了

但是在所有的 Dockerfile 中都使用上述地址比较繁琐,因此我们利用 nginx 来模拟一个 docker mirror 的实现,使得我们可以不去修改 image 名字而直接配置 docker mirror 就可以了。

创建 Robot Account

即使前面创建 Project 时设置 access level 为 public 这一步也是必要的

进入 Administration → Robot Accounts 创建一个新的机器人账号,为它授予我们 docker mirror harbor project 的 List Repositories 和 Pull Repositories 权限,记住展示的账号(`robot$` 开头)与 token

进入 Base64 Encode and Decode - Online 将账号和token 按照 robot$username:token 的形式输入,Encode 得到 Base64 备用(即准备利用 Basic Auth 进行认证)

配置 nginx

增加如下的 nginx server 配置

server { listen 443 ssl; server_name my-docker-mirror.example.com; ssl_certificate /certs/cert.pem; ssl_certificate_key /certs/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; location = /v2/ { proxy_pass http://HARBOR/v2/; proxy_set_header Host HARBOR; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Authorization 'Basic TOKEN'; } location ~ ^/v2/(.*)$ { proxy_pass http://HARBOR/v2/docker/$1; proxy_set_header Host HARBOR; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Authorization 'Basic TOKEN'; } }
  1. server_name 是你的自定义域名,后续将 docker mirror 的域名配置为这个即可

  2. docker mirror 必须为 HTTPS(尽管文档说可以支持 HTTP,但我测试并不行),因此必须准备好证书

  3. proxy_pass 与 proxy_set_header Host 中的 HARBOR 是你原来 harbor 的域名

  4. proxy_set_header Authorization 中的 TOKEN 替换为上面步骤中生成的 base64

配置 Docker

https://docs.docker.com/docker-hub/mirror/#configure-the-docker-daemon

记得一定将 docker mirror 配置成类似 https://my-docker-mirror.example.com 的形式,scheme 必须为 https 且不可省略

虽然文档中说了可以用 http,也说了可以省略 scheme 会自动用 https,但是实际可能版本问题,至少在我的版本下,不写 scheme 直接无法启动、写 http 也会强制使用 https