title: CI从入门到放弃
tags:

  • 持续集成
  • 自动化测试
  • 虚拟化

Introduce to GitLab CI

GitLab CI(Continuous Integration )从GitLab8.0开始就集成于GitLab中,后端的Runner使用.gitlab-ci.yml file 文件来描述对项目进行配置,.gitlab-ci.yml文件告诉GitLab运行器该做什么。 默认情况下,它运行一个包含三个stage的pipeline:构建,测试和部署。 你不需要使用所有三个stage; 没有job的stage会被忽略。

here's a growing trend to use continuous delivery and continuous deployment to automatically deploy tested code to staging and production environments.

运行一个CI需要有两步操作:

  1. 将.gitlab-ci.yml添加到存储库的根目录
  2. 配置一个Runner

Write a .gitlab-ci.yml

.gitlab-ci.yml文件是您配置CI对项目执行的操作的位置。 它位于存储库的根目录中。在任何推送到您的存储库时,GitLab将查找.gitlab-ci.yml文件,并根据该文件的内容在Runners上启动该提交的Job。

注意:.gitlab-ci.yml是一个YAML文件,所以你必须特别注意缩进。 始终使用空格,而不是制表符。

jobs

YAML文件定义了一组具有约束的job,说明应该何时运行它们。 您可以将job的顶级元素定义为任意名称,它们至少需要包含script子句。

job1:
  script: "execute-script-for-job1"

job2:
  script: "execute-script-for-job2"

job内的关键字

关键字 功能
script 由shell执行的脚本
stage job的stage,默认为test
variables job可见的环境变量
allow_failure 是否运行job失败
when 什么情况下执行job,可选on_success/on_failure/always/manual
only/except/tags 只在某些分支下执行job,指定执行job
artifacts job完成后把文件存在这个目录里
dependencies 依赖的job,可以用artifacts进行共享文件
coverage
before_script 覆盖在job之前执行的一组命令

stages

stages:
  - build
  - test
  - deploy

stages指定了各个stage的执行顺序

  1. 同一stage的job是并行运行的。
  2. 下一stage的job在上一stage的job成功完成后运行。

artifacts

artifacts指的是成功后应附加到job的文件和目录列表。job成功完成后,artifact将被发送到GitLab,并可在GitLab UI中下载

** artifacts:paths**:路径

**artifacts:expire_in ** 有效时间,默认为30天

dependencies

此功能应与artifact结合使用,并允许您定义要在不同job之间传递的artifact。请注意,默认情况下会传递所有先前阶段的artifact。

在CI中使用docker

Docker与GitLab CI一起使用时,使用.gitlab-ci.yml中设置的预定义镜像在单独且隔离的容器中运行每个job。

register a docker runner

使用sudo权限输入

sudo gitlab-runner register

接下来会提示输入gitlab仓库位置,tocken,以及使用的执行器,使用docker的话执行器就选择docker,然后选择镜像,这个配置以后可以通过修改配置文件进行修改,如果是通过root权限注册的,那么配置文件在/etc/gitlab-runner/config.toml文件中。

使用docker镜像的时候,默认是会从docker-hub下载镜像,如果镜像在本地,可以在config文件设置pull的policy:pull_policy = "if-not-present"或者pull_policy = "never"

[[runners]]
  name = ""
  url = ""
  token = ""
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "nb-node"
    privileged = false
    disable_cache = false
    volumes = ["/cache"]
+   pull_policy = "if-not-present"
  [runners.cache]

安装docker 和 nvidia-docker

ubuntu安装docker
Nvidia-Docker安装使用 -- 可使用GPU的Docker容器
具体安装方法参考官方github文档

值得注意的是上面的教程都是针对 nvidia-docker 1.0版本的,而最近我测试安装时不成功的,所以我安装了最新的nvidia-docker 2.0, nvidia-docker 2.0要求docker 版本为 18.06.0-ce,而这个版本的docker 使用apt-get 是无法安装的,所以我们从官网手动下载deb文件,进行安装。

docker 各版本下载位置

卸载老版本的docker

apt-get remove docker-ce

下载安装新版本的docker

wget https://download.docker.com/linux/ubuntu/dists/trusty/pool/stable/amd64/docker-ce_18.06.0~ce~3-0~ubuntu_amd64.deb 
dpkg -i docker-ce_18.06.0~ce~3-0~ubuntu_amd64.deb  
rm docker-ce_18.06.0~ce~3-0~ubuntu_amd64.deb  

然后安装nvidia-docker的github的方式安装nvidia-docker-2.

docker自定义远端仓库位置

docker切换默认镜像源
默认安装的 docker 镜像源是在国外,pull 镜像的时候奇慢无比,需要自己手动切换成国内的镜像源。
docker 默认的配置文件是 /etc/default/docker,如果此目录下不存在 docker 文件,可以自己手动创建一个,将文件中添加内容:

 DOCKER_OPTS=" --registry-mirror=https://【xxxxx】.mirror.aliyuncs.com" 

上述代码中的地址替换成自己想要更换的镜像源的地址即可,然后使用 service docker restart命令重启服务。
自定义的仓库可能需要通过 docker login 进行登录。

可以参考define-an-image-from-a-private-container-registry

如果要将私有docker仓库用作构建的镜像源,可以在DOCKER_AUTH_CONFIG秘密变量中设置授权配置。 它可以在项目的GitLab变量部分(网页端)和config.toml文件中设置。

在CI中定义镜像和服务

before_script:
  - bundle install

test:2.1:
  image: ruby:2.1
  services:
  - postgres:9.3
  script:
  - bundle exec rake spec

test:2.2:
  image: ruby:2.2
  services:
  - postgres:9.4
  script:
  - bundle exec rake spec

gitlabCI runner的结合使用例子

CI 手动调docker回传artifact 的一个例子

#image: cicuda8

build_arti:
  stage: build
  tags:
    - manual_docker
  script: 
    - hostname
    - mkdir build && cd build
    - touch tmp
    - echo "cd hostbuild && echo hello-world > tmp2" > tmp
  artifacts:
    expire_in: 1 day
    paths:
    - build/

test_arti:
  stage: test
  tags:
    - manual_docker
  script: 
    - sudo docker run --name test_manual_docker -i \
      -v $(pwd)/build:/hostbuild cicuda8 sh /hostbuild/tmp
    - sudo docker rm test_manual_docker
  dependencies:
    - build_arti
  artifacts:
    expire_in: 1 day
    paths:
    - build/
    
deploy_arti:
  stage: deploy
  tags:
    - manual_docker
  script:
    - cd build
    - cat tmp2
    - echo "end4"
  dependencies:
    - test_arti

CI通过SSH连接来调docker的例子

#image: cicuda8

build_arti:
  stage: build
  tags:
    - manual_docker
  script: 
    - hostname
    - mkdir build && cd build
    - touch tmp
    - echo "cd hostbuild && echo hello-world > tmp2" > tmp
  artifacts:
    expire_in: 1 day
    paths:
    - build/

test_arti:
  stage: test
  tags:
    - manual_docker
  script: 
    - cp /usr/share/expect_login.sh expect_login.sh
    - echo "send \"sudo docker run --name test_manual_docker -i -v $(pwd)/build:/hostbuild cicuda8 sh /hostbuild/tmp\r\"" >> expect_login.sh
    - echo "expect $*" >> expect_login.sh
    - echo "send \"sudo docker rm test_manual_docker\r\"" >> expect_login.sh
    - echo "expect $*" >> expect_login.sh
    - cat expect_login.sh
    - expect expect_login.sh 10.10.36.34
    #- sudo docker run --name test_manual_docker -i -v $(pwd)/build:/hostbuild cicuda8 sh /hostbuild/tmp
    #- sudo docker rm test_manual_docker
  dependencies:
    - build_arti
  artifacts:
    expire_in: 1 day
    paths:
    - build/
    
deploy_arti:
  stage: deploy
  tags:
    - manual_docker
  script:
    - cd build
    - cat tmp2
    - echo "end6"
  dependencies:
    - test_arti


这里使用了expect脚本:expect_login.sh

#!/usr/bin/expect
set timeout 30
set ip [lindex $argv 0]
spawn ssh -l maxiaolong 10.0.8.241
expect "password:"
send "mxl@lt.776688\r"
expect "Ip:*"
send "$ip\r"
expect "$*"
send "hostname\r"
expect $*
send ifconfig\r
expect "$*"
#interact

第二个例子 本地执行docker

stages:
  - build-default2
  - lint
  - test-default
  - build-more
  - test-more
  - build-python-full
  - test-python-full

build-default2:
  stage: build-default2
  variables:
    CC: "/usr/bin/gcc-4.8"
    CXX: "/usr/bin/g++-4.8"
    GTEST_ROOT: "/usr/local/gtest/gtest-4.8"
  tags:
    - manual_docker
  script:
    - mkdir temp && cd temp && touch scripts.sh mylog.log
    - git clone $CI_REPOSITORY_URL
    - echo "cd /temp && export CC=/usr/bin/gcc-4.8 && export CXX=/usr/bin/g++-4.8 && export GTEST_ROOT=/usr/local/gtest/gtest-4.8 " >> scripts.sh
    - echo "cd $CI_PROJECT_NAME	" >> scripts.sh
    - echo "git checkout $CI_COMMIT_REF_NAME" >> scripts.sh
    - echo "mkdir build && cd build/ && cmake ..  && make -j8 " >> scripts.sh
    - echo "cd ../python && make -j8 " >> scripts.sh
    - cat scripts.sh
    - cd -
    - sudo nvidia-docker run -i --rm  -v $(pwd)/temp:/temp  cicuda8:parrots2 sh /temp/scripts.sh
    - cat temp/mylog.log

第三个例子 上海集群执行docker

stages:
  - build-default
  - lint
  - test-default
  - build-more
  - test-more
  - build-python-full
  - test-python-full

build-default:
  stage: build-default
  variables:
    CC: "/usr/bin/gcc-4.8"
    CXX: "/usr/bin/g++-4.8"
    GTEST_ROOT: "/usr/local/gtest/gtest-4.8"
  tags:
    - ssh_docker
  script:
    - hostname
    - who -m
    - mkdir temp && cd temp && touch scripts.sh
    - echo "cd /$CI_PROJECT_NAME && export CC=/usr/bin/gcc-4.8 && export CXX=/usr/bin/g++-4.8 && export GTEST_ROOT=/usr/local/gtest/gtest-4.8 " >> scripts.sh
    - echo "cd $CI_PROJECT_NAME	&& hostname && pwd " >> scripts.sh
    - echo "mkdir build && cd build/ && cmake ..  && make -j8 " >> scripts.sh
    - echo "cd ../python && make -j8 " >> scripts.sh
    - cat scripts.sh
    - cd -
    - nvidia-docker run -i --rm  -v $(pwd):/$CI_PROJECT_NAME  registry.sensetime.com/platform/cicuda8:parrots2 sh /$CI_PROJECT_NAME/temp/scripts.sh


Configure a Runner

在GitLab中,Runners运行您在.gitlab-ci.yml中定义的作业。 Runner可以是虚拟机,VPS,裸机,docker容器甚至是容器集群。
get more information at GitLab Runner.

reference

"error while loading shared libraries: xxx.so.x" 错误的原因和解决办法
the docker excutor
Using Docker images
Getting started with GitLab CI/CD
[Configuration of your jobs with .gitlab-ci.yml](