关于CI系统(Continuous Integration),我已经有过了一些学习和实践了:

GitLab CI/CD (一) :自动打包部署Flutter项目 | DebuggerX’s Blog
GitLab CI/CD (二) :自动编译部署Web项目 | DebuggerX’s Blog
利用 GitHub Actions 自动构建 Linux 内核为 deb 包 | DebuggerX’s Blog

那么为什么还要再折腾这样一套CI方案呢?

  • GitLab的CI/CD:很好,很强大,功能非常完善,非常建议中小团队作为自建代码管理部署平台使用,唯一的问题就是太重了,需要一台性能配置颇高(至少使用2 vCPU和4 GiB内存)的独立服务器
  • GitHub Actions:也很好,使用非常方便,非常建议个人项目使用,但是同样缺陷明显,虽然可以部署私有runner,但是由于GitHub本身无法self-hosted,所以使用体验很受网络质量影响,并且由于各种安全限制,私有仓库使用体验不是那么的方便

所以基于如上原因,我是在家里一台24小时运行的小服务器上部署了一个 Gitea 服务,并将一部分个人项目托管在上面。最近在做的一个玩具项目里需要部署api接口供app使用,测试阶段接口也打算通过CI实时部署在内网的服务器上,于是决定在原有的Gitea上搭配部署 Drone

关于Drone

由于Drone和Gitea一样,都是使用go语言开发的,所以都可以支持在许多不同的平台下运行,运行时的资源开销也很小,具有很高的灵活性。

Drone作为一种“外挂式”CI系统,大致原理就是利用OAuth方式和Git service进行认证注册,然后利用Git service本身的web hooks作为本身的触发器,从而实现在代码被推送到服务器时能够自动触发CI运行。得益于这种通用灵活的实现方式,据文档显示,它官方支持的平台就有:

  • GitHub \ GitHub Enterprise
  • Gitea \ Gogs
  • Gitee
  • GitLab
  • Bitbucket Cloud \ Server

部署过程

略。。。参考文档即可,很简单……

遇到的问题:

  • 确保Git service、Drone和Grone runner之间的连通性。由于我的内网环境中有自定义的域名解析记录和端口映射,所以几部分之间是使用了域名+端口的方式互联,然后由于Drone是使用docker的方式部署,而正巧那台server上的docker设置了过多无用的虚拟网卡,导致了Drone在通过域名访问我的Gitea服务器时错误得将请求发到了docker自身创建的NAT网络中,结果是怎么都访问不通,最后在执行了 docker network prune 命令清理了无用的docker的虚拟网卡后问题解决
  • 我是用的Exec Runner,会在运行时在所部署机器的 /tmp 目录下创建一个虚拟环境拉取代码并执行CI脚本,所以一开始,在这个过程中发生的资源拷贝,我是打算通过系统的 $HOME 变量将资源写入家目录下,结果每次运行时会发现在指定的位置找不到资源,最终发现exec runner运行时读取到的 $HOME 变量并不是宿主机真实的家目录,而是虚拟环境的家目录,CI结束后会连同整个虚拟环境被一同销毁。所以暂时只能通过如下代码绕过:
    1
    2
    3
    4
    5
    DATA_ROOT="$HOME"

    if [[ "$DATA_ROOT" == /tmp/* ]]; then
    DATA_ROOT="/root"
    fi

效果截图

  • 项目CI统计界面
    1

  • runner日志界面
    2

  • CI运行及成功状态时Gitea中的状态显示:
    3

  • 整套系统资源开销

    • Gitea(按整个虚拟机的占用计算):约 150 MB
      4

    • Drone (按 Docker 中占用的资源计算) : 约 30 MB
      5

    • Runner (按进程所占资源计算) : 约 120 MB
      6

所以整个系统的内存占用大致是150 + 30 + 120 = 300 MB,512MB的服务器即可保证轻量实用。相较之下 GitLab 的内存配置需求是 4G 起步,相差足有一个数量级。