探索gitlab如何使用git实现基础功能及高可用

写在前面

最近有点分裂,一方面想把问题写得简单易懂,另一方面又发现有些概念只能通过持续地时间和精力投入才能精通甚至理解。心神不宁之季,写写文字记录自己的一些探索,聊以解闷。

一旦说到与Git,不得不提两个基于此技术的两个网页应用:GitHubGitLab。前者号称是全球最大的同志交友平台,理论上也差不多,因为平台汇聚的是全球的程序猿,而这个物种大都是男性(无语)。后者则因其开源的特性,应该是企业应用最多的私有化部署方案。

那么gitlab是如何调用git的服务完成代码管理的基础功能以及高可用的呢?

适用人群

入门——初级√——中级——高级;本文适应初级及以上。

Gitlab如何调用git仓库

在这之前,我已经知道git的工作机制,也能够通过git命令进行操作,但是对于gitlab这种代码仓库的架构一点概念也没有。比如说:

  1. gitlab如何与git仓库进行沟通?
  2. 从实用性来说,企业所搭建gitlab肯定是高可用的,那么git仓库的代码是保存在何处的?如何实现高可用的?(至少不能丢数据,那么如何做到不丢数据的?)

带着上面的两个疑问,我到源码中查到了一番。

(其实在此之前和几位同事讨论过此事,大家可能说不出具体的方案,但是各自在擅长的地方发表了一番看法,让我明确了大概的方向,抛出问题主动交流的重要性!

gitlab-ce源码初探

很庆幸gitlab有开源的社区版本(代码库地址见参考),这种免费的面包这个时候就特别解饿。

gitlab-ce源码是用Ruby on Rails编写的,而作为此技术栈出身的自己,读它的代码不在话下。我到/app/controllers/projects_controller.rb去找了半天(十分钟),但是半天过去了也没有发现明显的git仓库调用的接口。

因为Ruby元编程的特性,代码不一定藏在了什么地方,无奈,只能去google了(此时百度就表现出局限性了)。

pygit、ruby-git与JGit

从同事那边听到了pygit这个词,自己到github上搜到了ruby-git这个库,在git的官方地址看到了JGit这个工具。是的,这几个工具是对应语言的git接口库。

于是,我尝试在gitlab-ce源码中全局搜索ruby-git关键词,不过最终也没有找到。

最后找到了gitaly及gitaly-client

最终在gitlab-ce的源码库找到了lib/gitlab/gitlib/gitlab/gitaly_client,并且找到了 gitaly 这个仓库。

gitlab把一些平台相关的内容保存在数据库中(比如用户数据、项目信息等),而所有git版本仓库的数据则通过gitaly_client这个SDK与gitlaly进行RPC调用。

gitaly对git的使用进行了封装,通过查看其源码发现,这个工具所做的事情是对git命令的封装。即对gitaly而言,它的底层也是通过调用git这个命令实现的。可以通过查看internal/command/command.go,发现在发起命令前,会首先获取到git的二进制包路径,也就是说gitaly会像我们手动去git branchgit diff那样去做,只是它会对输出进行自动化解析,变成代码可理解的内容然后传回给gitlaly_client

gitlab高可用方案

当实现私有化部署时,最应关注的问题是高可用方案。这里面包括两层意思:1)一个是服务的高可用。跑demo式的做法肯定不可以,需要服务搭建者考虑一旦发生故障,该如何避免对用户的影响;一般的做法是启用多个副本同时提供服务,其中一个翘掉还有其他的可用。2)数据的安全。数据不能丢!数据不能丢!数据不能丢! 这个是重中之重,甚至比服务的高可用更重要。

通过上面的分析可以知道,gitlab最终通过封装git的二进制来实现代码的版本仓库功能库,那么数据层面的安全方案就自然而然变成了如何搭建一个高可用的git仓库

gitlab服务的高可用方案

服务多副本即可。比如,让gitlab的服务同时运行在两台物理机上,当请求到来时,负载均衡到这两台机器上面。或者把gitlab的服务部署在k8s中,如k8s中的基本概念所介绍的,启用两个Pod对外提供服务,通过Service把请求负载到这两个Pod上。

git的高可用方案

因为git本身就是分布式的,因此可以考虑把文件直接保存到多个文件系统副本。比如使用高可用NFS文件服务器保存git仓库的元数据。

高可用架构图

通过上面的分析,gitlab简易版的高可用架构图如下:

# 下面是gitlab简易版的高可用架构图
# 其中 高可用数据库用来保存gitlab中的
# 用户数据、项目信息等
# 
gitlab 多副本运行 ———— 高可用数据库(保存用户信息等)
    |
    |-------------(lib库引入)
gitaly-client
    |
    |-------------(RPC调用)
  gitaly
    |
    |-------------(通过调用git二进制包与git仓库沟通)
git仓库(多副本保存)

小结

本文对gitlab的架构进行了探索,主要围绕如何实现git仓库版本控制功能展开,基本确定:1)通过二次封装git命令调用原生的git仓库功能实现;2)gitlab封装了自己的git交互仓库gitaly;3)基于上面两点提出的一种gitlab的高可用方案。

需要说明的是,以上是纸上谈兵,只提供一种思路,在实际实施的过程中肯定会遇到各种坑,但是可以让大家对gitlab的架构有一个初步的认识。如果下次你所使用的gitlab服务出现故障时,或许能诊断出故障出在哪个地方,解答心中的疑惑。当然,本文也能给搭建并运维gitlab的新手一个指引,从而制定出符合自己环境的高可用方案。

参考