Gitlab-Runner原理与实现

应用场景:

通过技术手段保证gitlab中项目某个版本的可用性,当我想发布新版本时随实可以tag出一个可用的版本。与github配套的是travis,使用非常简单,只需要将github账户与travis绑定就可以选择保护的项目及版本,但是要在gitlab上实现类似的功能就只能靠自己来搭建了,今天就来介绍下gitlab-runner是如何工作的。

 

Gitlab/GitHub使用规范

示意图:

Gitlab-Runner原理与实现_第1张图片

注意事项:

1 Maintainer职责是最重要的,负责代码的review、approve merge、关心test结果,是master代码质量的第一负责人。

2 通过gitlab-runner运行pipeline,可以根据自己的需要编写复杂度不同的pipeline,初期只用在单元测试即可,fork版中的测试环节是非必需的,master版本中的测试环节是必须的。

 

Runner的实现原理:

示意图:

Gitlab-Runner原理与实现_第2张图片

Runner分为共享型(Shared Runner)和特享型(Specific Runner),因为gitlab项目语言种类和运行环境复杂多样,我们选用Specific Runner型。

 

 Gitlab与Runner的集成:

Gitlab-Runner原理与实现_第3张图片

 项目中添加.gitlab-ci文件定义runner要做的事情,tag决定哪个runner来执行。

 

实现细节:

1 安装gitlab

    在centos7上安装最新版本gitlab,我的版本是GitLab Enterprise Edition 11.3.4-ee

#安装依赖:
sudo yum install postfix
sudo systemctl enable postfix
sudo systemctl start postfix

#安装企业版gitlab
sudo yum -y install gitlab-ee

#修改gitlab访问地址和端口号(external_url)
sudo vi /etc/gitlab/gitlab.rb

#配置修改生效
sudo gitlab-ctl reconfigure

 按照自己配置的external_url去访问gitlab,首次登陆需要设置administrator的密码

2 安装 runner

  Runner分为共享型(Shared Runner)和特享型(Specific Runner)两种,共享型可以被gitlab上所有project公用;特享型绑定project只被指定使用。

  由于我的业务java、php、python各种语言都有,每条产品线运行环境也存在差异,所以倾向采用Specific Runner

  Runner可以安装在独立的vm内,也可以安装在容器内,这里的Specifig Runner我们运行在docker中。

  注意:runner不要与gitlab安装在一起,注册发现会有问题。

  2.1 准备docker环境

  docker的安装以前博文有介绍过,这里不再详解,重点是获取gitlab/gitlab-runner这个image。

  2.2 启动gitlab-runner

sudo docker run -d --name gitlab-runner --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

  2.3 注册runner到gitlab 

  先在gitlab的CI/CD页面找到url和token,如图

Gitlab-Runner原理与实现_第4张图片

#进入容器
sudo docker exec -it gitlab-runner /bin/bash
#容器中完成注册
gitlab-runner register \
  --non-interactive \
  --url "http://10.100.129.113:8090" \
  --registration-token "S1Erstg39-nh1xQVMtBN" \
  --executor "docker" \
  --docker-image maven:latest \
  --description "193runner " \
  --tag-list "193" \
  --run-untagged \
  --locked="false"

重要参数说明:

    url和token参考上图,在runner需要对接的gitlab中获得;

    executor是runner中pipeline以什么方式运行,这里选择的是docker方式,其实还支持shell等其它方式。

    docker-image是runner中pipelne以哪个image为基础来执行executor。

    tag-list是runner的tag,在gitlab的project中关于ci的配置文件中会引用得到。

Runner注册成功后就会在gitlab的CI/CD页面看到下图中的红框内容:

Gitlab-Runner原理与实现_第5张图片

如果出现灰色的runner说明runner虽然注册上来但是不可用,当gitlab与runner安装在同一台机器时就会出现这种情况,所以请尽量分开。

3 在gitlab的项目中配置gitlab-ci

    在项目根目录下添加.gitlab-ci.yml文件,gitlab-ci很强大,本质就是以yml的格式定义了一个pipeline,与jenkins存在功能重叠的部分,由于我们只是利用runner做项目master版本的单元测试,所以只需要在gitlab-ci中执行maven test。

     .gitlab-ci.yml内容如下:

image: maven:latest

stages:
  - test

job_test:
  stage: test
  script:
    - mvn test
  tags:
- '193'

4 配置user的权限

限制只有maintainers才可以push和merge项目的master版本

 

5 测试验证

  项目准备 maven-jdk1.8-Junit,可以在我的GitHub中直接下载:https://github.com/yejingtao/runproject.git

  验证步骤:

  5.1 maintainers直接操作

   以maintainers用户直接push,成功,同时触发pipeline。

  5.2 developer操做

     5.2.1 模拟直接提交

     用developer用户clone出runproject项目,直接push,因权限不足失败。

     5.2.2 fork 提交push到自己

     Developer用户从runproject项目中fork出自己版本,直接push可以成功,因为他是自己版本的maintainer

     5.2.3 发起PR

     Developer修改代码并push到自己fork项目后,发起PR

     5.2.4 maintainer用户mergePR

     Maintainer登陆gitlab后会看到RP通知,有两种merge方式:

Gitlab-Runner原理与实现_第6张图片

     下拉列表第一种是Developer自己的fork版本通过pipeline测试后再merge进master版本;第二种是直接merge进master版本。无论选择哪一种,都会触发master版本的一次pipeline。

     因为我们的目的只是保证master版本的可用性,所以推荐第二种。

     5.2.5 master revert本次操作

    如果merge一次PR后pipeline没有通过或者其他形式发现代码不可用,可以在PR页面找到当此PR,执行Revert。

Revert的本质其实就是以老版本重新发起一次PR,所以Revert后也会触发一次pipeline。

6 细节注意:

  1 .gitignore中记得要把.gitlab-ci.yml添加进去,不要被随意修改。

  2 如果要通过mvn test来做单元测试需要严格按照框架的命名规则,例如Junit默认测试Test结尾的类。

  3 Executor Image的选择要给予自己项目的场景,对于Specific Runner由研发自定义docker的image,可以提高执行效率。

 

Maven的依赖:

每次pipeline利用maven做单元测试时都会重新拉取代码的依赖包,如果有办法利用volume等手段缓存依赖的话可以提高测试效率。

理解了前面的原理,缓存的设置需要做两部份工作:1如何在docker中通过volume让maven的仓库可以直接在宿主机上挂载;2如何在gitlab-ci中进行配置。

volume挂载:

修改/srv/gitlab-runner/config/config.toml文件,我们从前面docker命令-v就可以看得出修改这里其实就是在修改runner容器中注册的问题件,修改如下:

[[runners]]
  name = "193runner"
  url = "http://10.100.129.113:8090"
  token = "327781c1630cef378aa4c62441a4e4"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "maven:latest"
    privileged = false
    disable_cache = false
    volumes = ["/var/runcache:/cache:rw"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

volumes这一行是关键,把宿主机的/var/runcache目录挂在到maven executor容器的/cache盘符下,并赋予读写权限。 

gitlab-ci配置:

在.gitlab-ci.yml中添加如下几行:

variables:
  MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=./.m2/repository"

cache:
  paths:
    - ./.m2/repository

对比下优化的效果:

优化前:

优化后:

可以看到效率得到明显的提高,再让我们看下宿主机的/var/runcache中到底有什么:

Gitlab-Runner原理与实现_第7张图片

可以看到/var/runcache/${gitlab_username}/${project_name}/default目录下有个cache压缩文件,解压后里面就是.m2仓库文件了,里面就是项目缓存的依赖包了。

你可以修改项目的pom.xml添加新的依赖,再来这个cache中看下就可以确定自己的猜测了。 

gitlab版本问题: 

gitlab与runner的版本需要匹配使用,如果版本不匹配会出现runner无法注册、runner注册后无法连接、runner无法运行executor等一系列莫名其妙的错误。

例如我公司由于历史包袱的原因,现在使用的gitlab是企业版8.1,我就在搭建这套环境中吃够了苦头。

1 gitlab-runner是9.0以后的产品,它的前身是gitlab-ci-multi-runner,所以用gitlab-runner是无法注册成为gitlab的runner的,像我的gitlab8.1版本的gitlab-ci-multi-runner对应的是1.8.5版本,下载地址:https://packages.gitlab.com/runner/gitlab-ci-multi-runner/packages/fedora/21/gitlab-ci-multi-runner-1.8.5-1.x86_64.rpm

2 .gitlab-ci.yml中的cache是gitlab8.2版本添加的属性,所以在我公司的版本中会报无法识别的错误,需要去掉。如果你想多个maven的executor之间共享local repository,可以修改config.toml中的volume,把宿主机的一个目录挂到executor的容器中去,然后在config.toml的variables中指定maven的本地仓库,例如:MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=/root/.m2/repository"

 

你可能感兴趣的:(持续集成)