使用 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 镜像,因此我们直接下载相应系统的官方镜像,然后在容器中直接配置环境。

综上,我们选定如下部署路线:

  1. 下载相应系统的镜像,创建容器
  2. 在容器中安装 R 软件
  3. 在容器配置 R 包编译环境
  4. 在容器中安装 GitLab Runner 并进行注册
  5. 在 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.04focal
18.04bionic
16.04xenial

R 版本号取决于要安装哪个 R 的版本

版本号填写内容
4.0cran40
3.5, 3.6cran35

例如,如果想使用 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 updateapt install 即可安装。

Debian

安装方法总体和 Ubuntu 一样,但是系统版本代号不太一样,但是一样可以通过 cat /etc/os-release 查看

版本号系统版本代号
10buster
9stretch
8jessie

然后使用如下命令认证密钥

1
apt-key adv --keyserver keys.gnupg.net --recv-key 'E19F5F87128899B192B1A2C2AD5F960A256A04AF'

之后同样使用 apt 安装即可。

openSUSE

这个安装比较简单,但是我在使用 Leap 15.2 版本的时候总是会卡住,所以最好还是使用 Leap 15.1 或版本。安装方法是运行如下命令

1
2
3
VERSION=$(grep "^PRETTY_NAME" /etc/os-release | tr " " "_" | sed -e 's/PRETTY_NAME=//' | sed -e 's/"//g')
zypper addrepo -f http://download.opensuse.org/repositories/devel\:/languages\:/R\:/patched/$VERSION/ R-base
zypper install R-base=4.0.3

指定版本号非常重要,不然会安装 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
2
3
4
# 清华大学 CRAN 镜像
options("repos" = c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))
# GWmodel CRAN 镜像
options("repos" = c(CRAN="http://gwmodel.whu.edu.cn/mirrors/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
2
3
4
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | bash
export GITLAB_RUNNER_DISABLE_SKEL=true
dnf install gitlab-runner
gitlab-runner install

这样应该就安装好了。

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

然后程序会问几个问题

  1. GitLab 网址
  2. Runner 注册的 Token
  3. Runner 的名字
  4. Runner 的标签
  5. Runner 的运行方式(这里选择 shell )

以上问题可以根据官方文档进行填写,网上资料也比较多。

注册完,就可以使用如下命令启动了

1
gitlab-runner start

在 GitLab 仓库中编写持续集成配置文件

如何编写持续集成配置文件,是个非常复杂的问题。这篇博客就不详细讲解了。 这里贴出来我们写好的文件,然后提几个注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
stages:
- build
- test

variables:
GWMODEL_VERSION: 2.2-0

build:
stage: build
tags:
- GWmodel
- Ubuntu
only:
refs:
- master
script:
- R CMD build GWmodel
artifacts:
paths:
- GWmodel_$GWMODEL_VERSION.tar.gz

test_cran_ubuntu:
stage: test
tags:
- GWmodel
- Ubuntu
only:
refs:
- master
script:
- R CMD check GWmodel_$GWMODEL_VERSION.tar.gz --as-cran
dependencies:
- build

test_cran_debian:
stage: test
tags:
- GWmodel
- Debian
only:
refs:
- master
script:
- R CMD check GWmodel_$GWMODEL_VERSION.tar.gz --as-cran
dependencies:
- build

test_cran_openSUSE:
stage: test
tags:
- GWmodel
- openSUSE
only:
refs:
- master
script:
- R CMD check GWmodel_$GWMODEL_VERSION.tar.gz --as-cran
dependencies:
- build

test_cran_Fedora:
stage: test
tags:
- GWmodel
- Fedora
only:
refs:
- master
script:
- R CMD check GWmodel_$GWMODEL_VERSION.tar.gz --as-cran
dependencies:
- build

test_cran_windows:
stage: test
tags:
- GWmodel
- Windows
only:
refs:
- master
script:
- R.exe CMD check GWmodel_$GWMODEL_VERSION.tar.gz --as-cran --no-manual
dependencies:
- build

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 包持续集成的所有配置方法。 如有不详细的地方,还请在评论区指出。

感谢您的阅读,本文由 HPDell 的个人博客 版权所有。如若转载,请注明出处:HPDell 的个人博客(http://hpdell.github.io/编程/RPackage-GitlabRunner/
QGIS 二次开发笔记(3)——空间距离和空间权重
游戏《原神》开服一周年有感