最近为了搞云原生基建,自建了一个Harbor镜像站用,应用程序本身支持提供https,但是由于现有服务比较多,在内网反代时一般是使用http协议,在最外层网关跑配置证书以支持https,统一管理证书有利于自动程序去及续期,减少人工负担。

我在搭建harbor的时候并没有启用https,所以只开放了80端口,发往CDN的https和http流量都会经由80端口到达Harbor

请求流程如下

graph LR A[客户端] --> B["CDN节点(https)"] B --> C["源服务器Nginx(https)"] C --> D["容器Nginx(http)"] D --> E["服务端点(http)"]

部署好整套服务之后,使用docker login reg.domain.com -u myusername交互输入密码后可以正常登录,也可以正常拉取需要权限的项目镜像。

但是当我尝试使用docker push时,服务器给我响应的是401 unauthorized。看容器日志也没看出个所以然,于是去Harbor GitHub仓库查询相关的issues,找到一个和我模式比较相似的部署实例也有类似的问题:Issue 3114

大致问题就是http位于https反向代理之后,但是harbor的一些服务不支持http这种不安全的传输方式。这种情况需要在每一个反代层配置X-Forwarded-Proto,但是由于我的CDN同时开放了80和443端口,推送在尝试80端口时连接成功,于是就是用http开始传输,目前有两个解决方案,一个是在最后一层反代处修改这个协议头为https骗一下程序,让它觉得所有请求都是https协议;另一个是把80端口关掉,从一开始就是用https,并且配置正确的协议头转发。

最省事的就是修改$HARBOR_ROOT/common/config/nginx/nginx.conf,找到map这部分修改,只用改动一处(最好不要去下面location路由改)

map $http_x_forwarded_proto $x_forwarded_proto {
    default https;
    ""      https;
}

改完之后sudo docker compose restart 即可,可以正常推送

最新进展:harbor tm就是一坨,但是也只有这坨好吃一点,其他的更难吃

CDN之后部署容器镜像站

如果你的容器镜像站(不仅仅是harbor)位于一个CDN或者反向代理后面,请勿自定义401状态码时的错误页面,因为命令行工具和v2 api通信需要这个响应状态码的响应体内容