之前harbor的高可用方案都是通过我们自建VIP与检测机制来做的,此次上线的双活架构下,VIP无法跨网段进行通信,甲方提供F5作为统一入口,由此进行了F5对接harbor的功能性测试。
问题现象
使用docker login harbor时,有时成功,有时失败:
1 | docker login -u user -p passwd http://xxx.xxx.xxx.xxx:9980 |
修改docker配置文件中镜像仓库地址为单独的harbor节点再次测试,没有任何问题。
问题分析
接着将docker镜像仓库地址换回F5地址,打开两个终端分别监视两个Harbor节点上的registry的日志。
经过几次测试,发现一个现象:当docker login成功时,都是一个节点上的日志出现更新;而当docker login fail时,会看到两个节点上的registry日志都有变化,这就有些出乎意料了。
查阅harbor官方对docker login的流程解析
- docker向registry发起请求,由于registry是基于token auth的,因此registry回复应答,告诉docker client去哪个URL去获取token;
- docker client根据应答中的URL向token service(ui)发起请求,通过user和passwd获取token;如果user和passwd在db中通过了验证,那么token service将用自己的私钥
(harbor/common/config/ui/private_key.pem)
生成一个token,返回给docker client端; - docker client获得token后再向registry发起login请求,registry用自己的证书
(harbor/common/config/registry/root.crt)
对token进行校验。通过则返回成功,否则返回失败。
从这个原理,可以知道问题就出在docker client多次向Harbor发起请求这个环节:对于每次请求,F5会将域名可能解析为不同IP,因此不同请求可能落到不同的镜像仓库节点上。这样当docker client拿着节点1上token service分配的token去到节点2的registry上鉴权时,就会出现鉴权失败的情况。
解决策略
token service的私钥(harbor/common/config/ui/private_key.pem)
和registry的证书(harbor/common/config/registry/root.crt)
都是在prepare时生成的,两个节点都独立prepare过,因此两个node上的private_key.pem和root.crt是不同的。所以造成了鉴权失败的问题。统一两个节点的私钥和证书可以解决。
将节点1上的private_key.pem和root.crt复制到节点2上,并重新创建node2上的harbor container。