问题背景
基于 rancher v2.8.5 搭建 rke2 集群时,默认情况下 containerd 默认拉取的各种镜像如下片段所示:
......
docker.io/rancher/rke2-runtime:v1.28.10-rke2r1
docker.io/rancher/klipper-lb:v0.4.7
docker.io/rancher/mirrored-pause:3.6
......
因为网络原因,服务器不能直接从 dockerhub 上拉取镜像。
我们有自己搭建的Harbor镜像私服,harbor 中创建了 dockerhub 的代理项目,名为 dockerhub_proxy
,私服可以正常代理 dockerhub 上的镜像,假设我们的 harbor 私服域名是 https://harbor.shanhy.com
。
所以我们通过 harbor 拉取上面的镜像就需要将 docker.io
修改为 harbor.shanhy.com/dockerhub_proxy
,示例如下:
harbor.shanhy.com/dockerhub_proxy/rancher/rke2-runtime:v1.28.10-rke2r1
harbor.shanhy.com/dockerhub_proxy/rancher/klipper-lb:v0.4.7
harbor.shanhy.com/dockerhub_proxy/rancher/mirrored-pause:3.6
虽然 Rancher 在创建新的 K8s 集群时,允许配置自己的私服,但是因为规范要求,私服地址只能是合法的域名地址,不能带有 path 后缀,所以不允许我们填写 harbor.shanhy.com/dockerhub_proxy
这样的带有 path 路径的 url 作为私服地址的。
Rancher 截稿 v2.8.5 虽然提供了 rewrite 镜像地址的功能,但是存在 bug ,不能用,希望后续版本能解决。
如果我们只填写 harbor.shanhy.com
,拉取镜像自动拼接后的地址 harbor.shanhy.com/rancher/rke2-runtime:v1.28.10-rke2r1
是无法拉取镜像的。因为 harbor 的设计必须要带有项目名称 dockerhub_proxy
这一段路径尾巴(截稿时 harbor v2.10.x,我给官方提了 issue#20829、issue#17791,被官方拒绝了) 。
有人对我这个 issue 进行评论,提供了通过 nginx 重写 location 的方式来变通解决这个问题(感谢 issue#8082_issuecomment-725694016)。
段落总结:
我希望通过独立的域名 harbor-dockerhub-proxy.shanhy.com
不带有 path 后缀,来直接访问 harbor 中的项目镜像。
即将 harbor-dockerhub-proxy.shanhy.com/rancher/mirrored-pause:3.6
对应到原始地址 harbor.shanhy.com/dockerhub_proxy/rancher/mirrored-pause:3.6
的实际效果。
Nginx 配置实战
通过在 nginx 中重写 path 的方式,实现上文需求。
1、登录 harbor,创建机器人账户,因为我们需要将密码配置到配置文件中,所以使用机器人账户缩小权限是有必要的。
- 系统权限:不需要选择
- 项目权限:选择所需要项目,权限全选或者按需勾选
- 有效期:永不过期或者按需设置
- 密码:生成的随机字符串密码拷贝记录下来
机器人账户类似一个临时的账户(也可以作为长期的来使用),机器人账户无法登录 Harbor 界面,机器人账户可以在命令行使用 docker login 进行登录。
2、将账户名和密码拼接起来生成base64字符串
按照格式 robot$robot-dockerhub:P2Ac8mcme88sdwefsdfs0xxlXGD3
拼接成字符串,使用 Linux 命令或者其他工具生成 base64 字符串。
echo 'robot$robot-dockerhub:P2Ac8mcme88sdwefsdfs0xxlXGD3'|base64
生成的 base64 字符串,在 nginx 配置文件中设置 header
Authorization
时使用。
3、nginx 配置文件
以独立域名 harbor-dockerhub-proxy.shanhy.com
对应 harbor 项目 dockerhub_proxy
为例的配置文件如下:
server {
listen 443 ssl;
server_name harbor-dockerhub-proxy.shanhy.com;
ssl_certificate /etc/letsencrypt/shanhy.com/cert.pem; # 指定证书的位置,绝对路径
ssl_certificate_key /etc/letsencrypt/shanhy.com/key.pem; # 绝对路径,同上
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&guideline=5.6
ssl_protocols TLSv1.2 TLSv1.3;
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;
ssl_prefer_server_ciphers off;
location ~ ^/v2/(?<path>.*)$ {
if ($path != "") {
# inject project and source domain into uri
set $path "dockerhub_proxy/$path";
}
proxy_pass https://harbor.shanhy.com/v2/$path;
proxy_cache off;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Authorization "Basic cm9ib3QkVpMdTdOZTZ6V2FHYWxYRlYyCg==";
proxy_read_timeout 900;
# prepare delegate auth
proxy_hide_header Www-Authenticate;
}
location ~ ^/service/ {
if ($args ~* "^(.*)(scope=repository%3A)(.*)$") {
# inject project and source domain into the auth scope
set $args "$1$2dockerhub_proxy%2F$3";
}
proxy_pass https://harbor.shanhy.com$uri$is_args$args;
proxy_cache off;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# /service/ 对Authorization的配置不是必要的
# proxy_set_header Authorization "Basic cm9ib3QkVpMdTdOZTZ6V2FHYWxYRlYyCg==";
proxy_read_timeout 900;
}
}
主要是 server_name 和 两段 location 的配置,有关 ssl 证书的配置和常规 nginx 配置证书一样,没有特殊之处。
(END)