使用 GitLab Runner 为 R 包配置持续集成服务
主要目的
众所周知,R 是一个跨平台统计软件,支持 Debian Ubuntu Fedora openSUSE Windows macOS 等多种平台。 R 中提供了众多的软件包,以实现各种功能。这些包被托管在 CRAN 上。 我们如果写了自己的软件包,也是要发布到 CRAN 上,但是其要求会特别严格,需要这些包在所有平台上编译通过。 R 提供了一个命令 R CMD check --as-cran
以在本地实现模拟 CRAN 编译环境的测试命令。 如果我们可以配置一个持续集成服务,在我们代码更新后直接在这些平台上进行测试,如果通过了就发布到 CRAN 上, 不仅可以大大减少手动测试的工作量,也能尽早发现错误。
平台选择
但问题是,基于什么平台配置这个持续集成服务?
目前提供持续集成服务的平台非常多,例如 Travis, Jekins, Github, Gitlab …… 这些平台有的可以自己部署,有的只能使用公有服务;有的使用脚本配置,有的基于 Docker 。 面对这么多平台,我们需要考虑到 R 和 R 包编译环境本身的特点:
- 与其他软件相比,R 并不那么常用,所以几乎没有现成的 Docker 镜像可以使用;
- 检查 R 包所需要的依赖包可能非常多,光是
R CMD check
命令执行所需要的包就有十数个,编译环境的配置比较复杂; - R 包所需要测试通过的平台比较多,尤其涉及 Windows ,这些平台环境的配置方法也不甚相同。
最后基本没得选,只剩下了 GitLab Runner ,几乎只有它能同时满足以上条件。 而且我们之前也部署了一个 GitLab ,使用 GitLab Runner 顺理成章。
但是由于需要测试这么多平台,虽然我们有一个 ESXi 平台,但是创建虚拟机有点太奢侈和复杂了,毕竟 GitLab Runner 也就是个小软件。 我们可以使用 Docker 容器替代虚拟机。使用 Docker 容器,我们只需要下载相应的镜像,创建容器,在容器中配置环境即可。 由于缺乏经验,能力尚不足以直接构建好相应的 R 镜像,因此我们直接下载相应系统的官方镜像,然后在容器中直接配置环境。
综上,我们选定如下部署路线:
- 下载相应系统的镜像,创建容器
- 在容器中安装 R 软件
- 在容器配置 R 包编译环境
- 在容器中安装 GitLab Runner 并进行注册
- 在 GitLab 仓库中编写持续集成配置文件
根据以上路线,我们成功配置好了 5 个 GitLab Runner ,实现了在不同系统上的持续集成。
部署方法
创建容器
下载镜像和创建容器就详解了,网上到处都是资料。 而且由于我们是在群晖中部署的,所以基本只是点了点鼠标。 命令行的方法我就暂时不介绍了。
所需要注意的是对于 Fedora 系统,为了方便配置 GitLab Runner ,启动脚本请使用 /sbin/init
而不要使用 /bin/bash
以防系统无法启动服务,而且还要使用高级权限运行。
安装 R 软件
首先需要安装 R 。在不同系统上安装 R 的方法,都写在 CRAN 中。 这里总结一下 Linux 系统的安装方法,因为 Windows 和 macOS 有图形界面,安装很方便。
Ubuntu
修改 apt 源,将以下内容放到 /etc/apt/sources.list
(或 /etc/apt/sources.list.d
目录下的文件)中
1 | deb http://<CRAN地址>/bin/linux/ubuntu <系统版本代号>-<R版本号>/ |
CRAN 地址可以使用官方地址,但是国内速度较慢,不建议使用。可以使用如下镜像地址:
- 清华大学:
mirrors.tuna.tsinghua.edu.cn/CRAN
- GWmodel :
gwmodel.whu.edu.cn/mirrors/CRAN
使用方法就是把后面的域名和路径替换 <CRAN地址>
的部分。
系统版本代号可以使用命令 cat /etc/os-release
查看,几个 LTS 版本的版号如下
版本号 | 系统版本代号 |
---|---|
20.04 | focal |
18.04 | bionic |
16.04 | xenial |
R 版本号取决于要安装哪个 R 的版本
版本号 | 填写内容 |
---|---|
4.0 | cran40 |
3.5, 3.6 | cran35 |
例如,如果想使用 GWmodel 的 CRAN 镜像地址,那么就使用如下 apt 源
1 | deb http://gwmodel.whu.edu.cn/mirrors/CRAN/bin/linux/ubuntu bionic-cran40/ |
然后,认证密钥,使用如下命令
1 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 |
之后使用 apt update
和 apt install
即可安装。
Debian
安装方法总体和 Ubuntu 一样,但是系统版本代号不太一样,但是一样可以通过 cat /etc/os-release
查看
版本号 | 系统版本代号 |
---|---|
10 | buster |
9 | stretch |
8 | jessie |
然后使用如下命令认证密钥
1 | apt-key adv --keyserver keys.gnupg.net --recv-key 'E19F5F87128899B192B1A2C2AD5F960A256A04AF' |
之后同样使用 apt 安装即可。
openSUSE
这个安装比较简单,但是我在使用 Leap 15.2 版本的时候总是会卡住,所以最好还是使用 Leap 15.1 或版本。安装方法是运行如下命令
1 | VERSION=$(grep "^PRETTY_NAME" /etc/os-release | tr " " "_" | sed -e 's/PRETTY_NAME=//' | sed -e 's/"//g') |
指定版本号非常重要,不然会安装 R 3.5 版本。
Fedora
这个安装更加简单,官方库自带了 R ,所以直接使用如下命令安装
1 | dnf install R |
需要注意的是, Fedora 32 和 33 有 4.0 版本的 R ,之前的版本只有 3.6 版本的 R 。
配置 R 包编译环境
主要就是安装依赖包了,这个就和要进行持续集成的 R 包本身相关了。 可以直接运行一次 R CMD check
命令查看有哪些依赖包没有安装。
安装包推荐设置 CRAN 镜像,这时的设置方法是将如下语句放在 Rprofile 文件中(根据使用的镜像不同选择不同的地址)
1 | # 清华大学 CRAN 镜像 |
如果你的包依赖了 sf
包,那么在各个系统下需要安装如下依赖库(不是在 R 中安装)
- Ubuntu & Debian : libgdal-dev, libudunits2-dev
- Fedora: gdal-devel, libproj-devel, geos-devel, udunits2-devel, sqlite-devel
- openSUSE: gdal-devel, libproj-devel, geos-devel, gdal, proj 然后 udunits2 手动编译安装
其他依赖库也都是通过包管理器安装,这样 R 包的依赖才能通过。
安装 GitLab Runner 并进行注册
Windows 和 macOS 系统就不说了,非常简单。 Ubuntu 和 Debian 上也有官方教程,直接可以照着做。 Fedora 和 openSUSE 就会遇到奇奇怪怪的问题,尤其是运行 gitlab-runner install
会报系统不支持。 这里主要总结一下 Linux 系统的。
Ubuntu 和 Debian 上的安装
Ubuntu, Debian 可以参考官方文档)进行安装,推荐使用包管理方式。如果有依赖问题解决以来问题即可。
Fedora 32 上的安装
之所以说 Fedora 32 ,因为官方没有明确支持这个版本,支持 Fedora 30 ,但是 Fedora 30 并没有 R 4.0 的包。但是经过实测, Fedora 32 确实可以安装 GitLab Runner 只是要解决一些问题。所以这个方法只保证这个系统有效,其他版本并不保证。
安装前,容器中可能没有 service 命令,可以通过安装 initscripts
命令进行解决。 此外建议安装 lsb
包。
还记得一开始说容器的启动脚本要使用 /sbin/init
吗?这使得容易可以启动服务。如果使用 /bin/bash
启动的话,即使装了 service 命令,也可能无法启动服务。
然后使用官方软件包进行安装
1 | curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | bash |
这样应该就安装好了。
openSUSE Leap 15.1 上的安装
这个明确的讲,使用的是奇技淫巧,不能保证永远可行。
首先下载 gitlab-runner 二进制文件并放到 PATH
路径中(架构根据实际情况调整)
1 | sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64 |
然后安装 initscripts
包,并准备以下文件,可以从 Ubuntu 中复制
/etc/init.d/gitlab-runner
/lib/lsb/init-functions
然后建立 /etc/rc.d/rc0.d
文件夹,在其中建立软链接
1 | ln -s /etc/init.d/gitlab-runner /etc/rc.d/rc0.d/K20gitlab-runner |
然后,直接运行 gitlab-runner start
应该就可以启动了。
其实,
gitlab-runner install
命令只是创建以下服务,这个过程手动创建也是可以的。 上面就是模拟了手动创建的过程。如果你水平比较高,可以自己写服务启动脚本,就不需要从 Ubuntu 复制了。
GitLab Runner 的注册
注册非常简单,在所有系统上都是一样的,使用如下命令
1 | gitlab-runner register |
然后程序会问几个问题
- GitLab 网址
- Runner 注册的 Token
- Runner 的名字
- Runner 的标签
- Runner 的运行方式(这里选择 shell )
以上问题可以根据官方文档进行填写,网上资料也比较多。
注册完,就可以使用如下命令启动了
1 | gitlab-runner start |
在 GitLab 仓库中编写持续集成配置文件
如何编写持续集成配置文件,是个非常复杂的问题。这篇博客就不详细讲解了。 这里贴出来我们写好的文件,然后提几个注意事项
1 | stages: |
Stages 和任务
yml 文件第一级的标签名,默认为是任务名,除非是一些特别的关键字,如 stages
。 这里面标识了不同任务所处的阶段,按顺序排列,名字随意。 只有一个阶段的任务全部通过,才执行下一个阶段的任务。 这里第一个阶段 build
构建一个源码包。这个阶段就无需分系统进行,只有测试才需要分系统进行。
任务中的 tags
一个任务执行只使用一个 Runner ,具体使用哪个 Runner ,就是通过 tags 选择的。 所以这里的 tags 要和创建 Runner 时设置的 tags 相对应。
任务中的 artifacts 和 dependencies
如果一个任务想留下一些东西给后续任务使用,就需要使用 artifacts
指定留下哪些东西。 这些东西也可以在 GitLab 上进行下载。 这里我留下了 build 命令生成的压缩包,供后续 check 过程使用。
如果一个任务想使用之前任务留下来的东西,就需要使用 dependencies
指定获取哪些任务遗留下来的文件。 因此,所有执行 test
阶段的任务都依赖于 build
那个任务即可。
其实最后还应该有一步部署,理论上可以直接上传到 CRAN 中。但是这个还没研究出来怎么做,先挖个坑。
使用
R CMD check --as-cran
会尝试编译文档,因此需要 latex 。这个最好还是安装以下。 如果不想安装,可以仿照test_cran_windows
中添加--no-manual
参数,就不会编译 pdf 版的文档了。
以上就是使用 GitLab Runner 进行 R 包持续集成的所有配置方法。 如有不详细的地方,还请在评论区指出。