持续集成

持续集成介绍

在软件工程中,持续集成(CI)是指将所有开发者的工作副本每天多次合并到主干的做法。Grady Booch 在1991年的 Booch method 中首次命名并提出了 CI 的概念,尽管在当时他并不主张每天多次集成。而 XP(Extreme programming,极限编程)采用了 CI 的概念,并提倡每天不止一次集成。

持续集成在现代软件研发流程中,扮演了十分重要的角色。通过对每次提交的代码不断进行自动化的单元测试、代码检查、编译构建、契约测试,甚至自动部署,持续集成大大降低了开发人员的工作负担,减少了不必要的重复劳动,提升代码质量和开发效率。毫无疑问,持续集成是开发者和研发团队的福音。

当我们提交了一部分修改完成的代码后,我们总是希望可以快速、持续地得到直观且有效的反馈,以达到我们持续快速交付的目的。持续集成也是敏捷开发的好伙伴。Jenkins工具则是我们达到目的的利器。

我们在平时的工程中,总有一部分工作是相对机械化,易出错的(例如部署,打包),把这部分工作较给机器来做,我们仅需要轻轻地点一下鼠标泡杯咖啡就能让自己轻松地完成工作。

持续集成服务器就是能够采用自动化的手段,来解放人的双手,实现项目持续集成的工具。

然而想在项目和团队中实施持续集成,却不是一件简单的事情。CODING 推出的持续集成beta服务,CODING 持续集成是基于 Jenkins 的,兼容 Jenkinsfile 配置文件,如果您之前有使用过或者写过 Jenkinsfile 相信您会很快上手。

持续集成的优势

1.解放了重复性劳动。
自动化部署工作可以解放集成、测试、部署等重复性劳动,而机器集成的频率明显比手工高很多。

2.更快地修复问题。
持续集成更早的获取变更,更早的进入测试,更早的发现问题,解决问题的成本显著下降。

3.更快的交付成果。
更早发现错误减少解决错误所需的工作量。集成服务器在构建环节发现错误可以及时通知开发人员修复。集成服务器在部署环节发现错误可以回退到上一版本,服务器始终有一个可用的版本。

4.减少手工的错误。
在重复性动作上,人容易犯错,而机器犯错的几率几乎为零。

5.减少了等待时间。
缩短了从开发、集成、测试、部署各个环节的时间,从而也就缩短了中间可以出现的等待时机。持续集成,意味着开发、集成、测试、部署也得以持续。

6.更高的产品质量。
集成服务器往往提供代码质量检测等功能,对不规范或有错误的地方会进行标致,也可以设置邮件和短信等进行警告。

创建持续集成

CODING 持续集成是基于 Jenkins 的,通过 Jenkinsfile 配置文件完成CI的步骤,接下来将引导您一步步创建一个持续集成示例。

图片

在任意一个项目的左侧有个持续集成的功能,点击后即可打开持续集成界面。点击【开始持续集成】进入下一步。

找到或者创建 Jenkinsfile

图片

CODING 持续集成服务支持通过项目中的 Jenkinsfile 和通过示例创建 Jenkinsfile 。 Jenkinsfile  简单来说就是一个配置持续集成流程的配置文件, 您可以参考 Jenkins 的官方文档 或者第三方的中文文档,了解 Jenkinsfile 是如何编写的。

我们这里直接选择简易示例进行创建,建议示例中的配置如下:

agent 中声明了构建环境,stages 中生声明了步骤,每个步骤都是可以自定义的。简易示例中预支了四个步骤,分别是检出、构建、测试、部署。其中只有检出有具体步骤其余都只是输出文本,用来展示每个步骤。

在检出那一步中通过 git 获取到了代码仓库中的代码,其中 env 代表系统变量,而 GIT_BUILD_REF 和 GIT_REPO_URL 是已经内置的系统变量,点击页面下方的构建按钮进入下一步。

我们来看一个完整的从拉取代码到上传到服务器的例子,这里只是用 Java 语言的项目举例,其它编程语言需要根据实际情况自行修改:

pipeline {
    agent {
        // 此处设定构建环境,目前可选有
        // java-8,python-2.7,python-3.5,build-essential,ruby-2.3,go-1.7
        label "java-8"
    }
    stages  {

     	stage("环境") {
            steps {
                parallel "Maven": {
                  	script{
                      	sh 'mvn -version'
                  	}
                }, "Java": {
                    sh 'java -version'
                }, "sshpass": {
                  	sh 'apt install -y sshpass'
                    sh 'sshpass -v'
                }
            }
          
        }
        
        stage("检出") {
            steps {
                sh 'ci-init'
                checkout(
                  [$class: 'GitSCM', branches: [[name: env.GIT_BUILD_REF]], 
                  userRemoteConfigs: [[url: env.GIT_REPO_URL]]]
                )
            }
        }

        stage("构建") {
            steps {
                echo "构建中..."
              	sh 'mvn package -Dmaven.test.skip=true'
                archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
                echo "构建完成."
            }
        }

        stage("测试") {
            steps {
                parallel "单元测试": {
                    echo "单元测试中..."
                    sh 'mvn test'
                    echo "单元测试完成."
                    junit 'target/surefire-reports/*.xml'
                }, "接口测试": {
                    echo "接口测试中..."
                    // 请在这里放置您项目代码的单元测试调用过程,例如 mvn test
                    echo "接口测试完成."
                    // 请在这里放置收集接口测试报告的调用过程,JUnit 示例:junit 'target/surefire-reports/*.xml'
                }

            }
          
        }
      	stage("运行"){
      		steps {
            	sh 'java -jar target/java-0.0.1-SNAPSHOT.jar'
    	    }
    	}
      	stage("部署"){
      		steps {
              parallel "上传": {
                    sh 'sshpass -p password scp target/java-0.0.1-SNAPSHOT.jar root@1.1.1.1:/root/'
                }, "运行": {
                    sh 'sshpass -p password  ssh root@1.1.1.1 java -jar /root/java-0.0.1-SNAPSHOT.jar'
                }
    	    }
    	}
 
    }
}

 

首先我们先新建了一个名为【环境】的步骤,然后同时执行 java、maven 的检查和 sshpass 的安装。我们需要在后面通过 sshpass 将构建物传输到服务器上。

在【构建】那一步中有一行 “archiveArtifacts artifacts: ‘**/target/*.jar’, fingerprint: true” ,这一行主要是声明构建物在哪里,这样target下的所有jar都会被当做构建物,显示在构建产物选项卡中。

我们最后再来看看【部署】这个步骤,【部署】这里通过 sshpass 将我们的编译结果通过命令行传输到指定服务器上,然后再通过 sshpass 连接到服务器上运行。

准备好 Jenkinsfile 后就可以进入下一步了,进入下一步后您会看到构建记录列表,在构建记录列表中能看到构建记录的状态、对应的版本、开始时间等信息。

图片

点击构建记录后可以看到可视化的构建过程,每个步骤都是可以点击的,点击后还能看到那个步骤的详细日志。

查看构建记录

当创建完成后会自动构建一次,如果您想调整构建过程的话可以随时点击右上方的配置按钮修改 Jenkinsfile 来调整构建流程。

点击构件记录进去可以看到更详细的步骤及日志:

每一个步骤都是可以点击的,如果哪一个步骤是成功的会自动变成绿色,如果不成功会变成红色的 X ,让您能够一目了然看到构建过程。点击每一个步骤都可以看到该步骤的日志输出,如上图就是在查看检出这个步骤的日志。

修改触发条件

图片

您可以在修改 Jenkinsfile 的时候修改触发方式,您可以自行选择是推送到某个标签或者某个分支时间触发构建。

当然您也可以在构建记录的右上角找到“配置”按钮。

预制系统环境变量

目前已经预制了几个可以在脚本中使用的环境变量:

GIT_COMMIT 当前的SHA
GIT_BRANCH 远程存储库的名称(默认为origin),后跟当前正在使用的分支的名称,例如“ origin/master”或“ origin/foo”
GIT_LOCAL_BRANCH 名称。如果配置了“检出特定本地分支”行为,则发布变量。如果行为配置为null或**,则该属性将包含生成的本地分支名称sans远程名称。
GIT_PREVIOUS_COMMIT 来自同一分支的先前构建的提交的SHA(未在分支上的第一次构建时设置)
GIT_PREVIOUS_SUCCESSFUL_COMMIT 来自同一分支的先前成功构建的提交的SHA (未在分支上的第一次构建时设置)
GIT_URL 存储库远程URL
GIT_URL_N 存在多个远程URL时的存储库远程URL,例如GIT_URL_1,GIT_URL_2
GIT_AUTHOR_NAME和GIT_COMMITTER_NAME 如果启用了“自定义用户名/电子邮件地址”行为,则输入的名称; 回退到“Global Config user.name Value”下的Jenkins系统配置中输入的值(如果有的话)
GIT_AUTHOR_EMAIL和GIT_COMMITTER_EMAIL 如果启用了“自定义用户名/电子邮件地址”行为,则输入的电子邮件; 回退到“Global Config user.email Value”下的Jenkins系统配置中输入的值(如果有的话)

执行时提供这些环境变量。由应用端这边准备好就行。这个是第一步,然后再用用户的自定义环境变量去覆盖。

如果是代码推送触发的持续集成,系统默认环境变量还应该带上 ref

添加一个默认的环境变量:
REF=refs/heads/master具体的值根据构建 CiBuild 里面记录的 branch 字段给定就行。

 

 

时区设置

jenkins 以及能够为 agent 默认配置好 timezone 和 localtime(默认中国上海)

如果需要配置其他时区可以在基础镜像里加图下这个指令,然后更新所有镜像就可以更新时区。


sh 'echo "Asia/Shanghai" > /etc/timezone'
sh 'cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime'
sh 'date'

支持的构建环境

CODING持续集成服务目前支持以下环境:

  • java-8
  • python-2.7
  • python-3.5
  • go-1.7
  • go-1.9
  • go-1.11
  • node-8
  • node-10
  • php-7.0
  • php-7.1
  • php-7.2
  • php-7.3
  • ruby-2.3
  • default: 包括了 java-1.8.0_181, go-1.7.4, node-10.11.0, php-7.0.30, ruby-2.3, python-2.7.13 等。

需要更多环境,请发邮件到support@coding.net联系运营小姐姐提出要求。

镜像优化

为了帮助构建更快,maven、gradle、npm、python、ruby 默认使用了腾讯云的源 https://mirrors.cloud.tencent.com/。php 目前支持了其他国内的源(https://packagist.phpcomposer.com)。