一、写在前面
这一篇是对搭建Gerrit集群环境时遇到的问题及解决方案的小结。不谈细节,我们搭建这个集群需要达到的最直接效果是:用户访问且仅访问一个Gerrit服务器地址,集群内任意服务器都有能力响应。这里说的“有能力”,由SSH传输协议展开。
二、集群服务器共享用户公钥
用户如果需要从Gerrit服务器上通过ssh协议下载数据,首先会在服务器上增加自己的公钥,从而让服务器在用户请求通信时向用户发送“质询”,验证用户身份。(更详细的说明在这:[Gerrit服务器集群搭建(二)] SSH原理及应用初步探索。)
那么第一个问题就来了,用户如何向这整个服务器集群增加公钥呢?让用户向集群中的每一台服务器手动添加公钥,这种麻烦的方法不到万不得已自然是不用的。很自然的,我们希望服务器能共享这些用户资料。
在共享之前首先当然要知道这些资料存放在哪里,遗憾的是,我翻遍所有Gerrit目录下的文件夹,也没看到一个形似用户资料的文件。当时我还是用的H2数据库,这个数据库倒是有几个文件在目录下。于是我脑子一拍,将整个数据库文件复制到了另一个Gerrit server上,不出所料,刷新该服务器后,用户信息全部过来了。当然,有了思路还是要进一步验证的,不过服务器不在身边,就不截图说明了。
后来查阅资料发现H2数据库有最大存储限制,256GB,虽说也不算小,但有限制总归让人没有安全感,并且考虑到今后如果数据库负载重也需要集群化,所以,最终我们选择了功能更加丰富的PostgreSQL。
用PostgreSQL,共享数据最直接的当然是集群化,详细步骤可参见postgresql集群方案hot standby 安装和测试。不过,等等,Gerrit初始化的时候还提供了一个数据库类型叫做JDBC,JDBC是什么呢?百度之,“JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Java语言中的接口和类,使用这些接口和类,Java客户端程序可以访问各种不同类型的数据库。”竟然还有接口支持,又涨了见识~看来事情还可以这样简化:在其中一台服务器建立数据库,其它服务器远程连接使用这台服务器上的数据即可。于是,就有了[Gerrit服务器集群搭建(一)]初识Gerrit代码审查系统中关于PostgreSQL配置和连接的过程。
(这里追加评论一下,这样做在我们实际使用中其实不太稳定,偶尔还会出现数据库查询失败的错误,前阵子主要希望快速上线,这部分粗糙了,找个周末人少时间多,我再去实践一下数据库集群。)
三、集群服务器共享SSH Key & Fingerprint
对用户而言,下载服务器的IP是唯一的,而实际上,用户下载请求将会被动态分配到不同的Gerrit server去响应。由于这些下载通过SSH协议,这个协议会记录下IP:Port与特定fingerprint的对应关系,本意是为了保护数据传输安全,但会给我们的架构带来问题:假设用户访问下载服务器(后简称VIP),第一次下载由服务器A响应,在用户的.ssh目录下known_host文件中,就会记录下VIP与服务器A的对应关系;第二次下载,该用户的下载请求被服务器B响应,此时用户主机检查VIP已与服务器A建立了对应关系,便会提示用户一个warning,拒绝下载,此时用户可以根据提示删除响应的对应关系解决,但这无疑是非常麻烦的。
似乎让集群所有服务器都使用同一个fingerprint是个可行的方案。
fingerprint依据且仅依据SSH public key通过MD5计算产生(。因此,共享fingerprint只需要共享SSH key。通常主机的SSH key都存在于$HOME/.ssh及/etc/ssh/下,但Gerrit server会根据内部监听的下载端口(默认29418),用server初始化时生成的SSH key去与用户进行连接。也就是说,通过Gerrit server下载,你会发现提示的fingerprint与SSH远程访问该主机的fingerprint不一样,因为它们由不同端口响应,对应了不同的SSH public key。
有了思路,解决就不困难了,server里的SSH key都存放在[gerrit_site]/etc/下, 复制同步即可。需要注意的是基于java 1.7版本和1.8版本初始化Gerrit生成的key文件形式不一样,如果服务器间java版本不同,可能需要将1.8版本server的[gerrit_site]/lib/下,bcprov-jdk15on-149.jar,bcpkix-jdk15on-149.jar这两个文件,复制到1.7版本的server中,让1.7版本能够支持1.8版本key的格式。