从“CI搭建兽”到“流水线即代码”

本文是2017年3月13日晚9点在“AHA面对面”线上分享的“单件流的力量-伍斌_Ben面对面”的操练步骤,这里是报名链接。

IMG_0861.PNG

操练目的

练习在CloudBees Jenkins Enterprise上手工配置部署流水线,使得每次代码提交,都能自动触发该部署流水线,并将这个过程可视化,以便一眼就能看到谁的代码提交在哪个环节引起了什么质量问题,以便快速进行修复。

因为本次操练的主要目的是手工搭建部署流水线,为节省时间,被部署的代码并不是一个完整的Web应用程序,而是使用了一个Java应用程序和一个Robot Framework (Python) Web UI自动化应用程序:前者仅仅是一个用Maven创建的有单元测试的简单Java应用,后者仅仅是Robot Framework官网上用于演示用的webdemo应用程序。用两者的结合来模拟一个完整的Web应用程序:前者模拟自动化单元测试,后者模拟自动化验收测试。

在ThoughtWorks中国区,大家亲热地把用手工搭建部署流水线的人称为“CI搭建兽”,意指这种手工配置过程既繁琐费神又毫无乐趣,比较原始,比那些已经进化的人所从事的工作要低级。;-))

而更加高级的工作应该是“流水线即代码”的实践,来让配置脚本能与代码一起进行版本控制。这样的好处是:Ops可以不用通过访问生产环境,就能知道生产环境上的配置情况;非运维人员如Dev,就有机会去学习这些运维配置代码并且加以修改,提升整个团队的DevOps能力;另外工具能方便地读取这些代码,来自动化地维护基层设施,大幅度提升Ops的工作效率。想了解更多相关的DevOps的良好实践,不妨阅读我的文章“实例化DevOps原则”。

为了知道“流水线即代码”到底有多甜,需要先吃一点“CI搭建兽”的苦。本文会先描述“CI搭建兽”的辛苦手工工作,最后会把这些手工工作用10行“流水线即代码”写出来并加以运行。

准备工作

环境准备

本文以macOS Sierra 10.12.3为例来准备环境。

  • 安装JDK 1.8
  • 安装Maven 3.3.9
  • 安装Git 2.10.1
  • 安装Python 2.7(macOS应该自带)
  • 安装Python包管理工具Pip 9.0.1
  • 安装Robot Framework 3.0.2
    pip install robotframework
  • 安装robotframework-selenium2library
    pip install robotframework-selenium2library
  • 安装Java IDE IntelliJ 社区版来编辑Java单元测试代码
  • 安装PyCharm 社区版来编辑Python Web UI测试代码
  • 准备测试代码:可以用下述命令git clone 本次操练的代码,其中mobilebanking文件夹存放了一个Java应用程序,robotframework-webdemo存放了一个Web UI测试程序;
    git clone https://github.com/wubin28/jenkins-mobile-banking.git
    • 也可以用下面的方法自己动手来创建和下载这两个程序:
      • 用下述Maven命令来创建一个带有单元测试的简单的Java应用程序mobilebanking
        mvn archetype:generate -DarchetypeCatalog=internal
      • 下载WebDemo-20150901.zip作为Web UI测试代码,并将该压缩包解压到文件夹robotframework-webdemo
  • 下载CloudBees Jenkins Enterprise,可以选择On-Premise来下载WAR包(v 2.46.2.1)

单独运行自动化单元测试

在配置流水线前,先看看Java应用程序的单元测试能否运行通过。

  • 打开命令行窗口,进入上述mobilebanking所在的文件夹,执行下面命令,
    mvn clean test

单独运行自动化Web UI测试

再看看Python的自动化Web UI测试程序能否正常运行。

  • 在命令行窗口中进入上述robotframework-webdemo文件夹,运行下面的命令来启动一个待Web UI测试的Web应用程序
    python demoapp/server.py
  • 用浏览器访问下面的链接,来查看待测试的Web应用程序;如果想成功登录这个Web页面,那么用户名请填写demo,密码请填写mode
    http://localhost:7272/
  • 在命令行窗口的robotframework-webdemo文件夹中,运行下面的命令来单独运行Web UI自动化测试。如果运行时发现浏览器驱动的错误,则需要另行下载安装相应的浏览器驱动程序,并配置到PATH环境变量里(例如,从chromedriver网站上下载Chrome浏览器驱动.ZIP文件,解压后,把相应的目录位置放到~/.bash_profile里面的PATH中,再source ~/.bash_profile使其生效)
    robot login_tests

运行CloudBees Jenkins并查看插件

再看看流水线所依赖的两个插件是否已安装。

  • 运行下述命令来启动CloudBees Jenkins
    java -jar jenkins.war
  • 打开浏览器访问下面的CloudBees Jenkins链接,在页面上选择Trial来申请14天的免费试用许可证
    http://localhost:8080/
  • 在首页上点击“Jenkins -> Manage Jenkins -> Manage Plugins -> Installed”来查看下面两个插件是否已经安装(CloudBees Jenkins Enterprise默认已经安装)
    • Delivery Pipeline Plugin
    • Robot Framework plugin

CI搭建兽的辛苦手工工作

先看看要搭建的流水线的样子。这个流水线有两个Stage:一个是COMMIT,用来针对第#53号代码提交运行自动化单元测试;另一个是ACCEPTANCE,用来在单元测试运行通过后,针对同样的代码提交运行基于Web界面的自动化验收测试。


要搭建的流水线的样子

创建流水线的第一个Stage:COMMIT

首先创建流水线的第一个Stage——COMMIT,来运行自动化单元测试。

  • 在Jenkins首页点击“New Item”链接
  • 在Enter an item name输入框中输入这个item的名字,比如可以叫mobilebanking-commit
  • 点击"Maven project",然后点击OK按钮,进入配置页面
  • 勾选“Delivery Pipeline configuration”,在下面出现的Stage Name输入框中,填写这个stage的名字,比如叫COMMIT;在下面的Task Name输入框中,填写这个stage的描述信息,比如叫Build mobilebanking and run unit tests
  • 在Source Code Management框中,选择Git,然后在下面的Repository URL输入框中填入Java源代码的位置,可以是github的地址,这里填写了本机地址file:///Users/twer/OOR/katas/remote/jenkins-mobile-banking
  • 在Build Triggers框中,勾选“Poll SCM”,并在Schedule框中填写* * * * *,表示每分钟Jenkins会查看是否有代码提交进而触发自动化单元测试;* * * * *这种写法对这次操练很有用,但在实际工作环境中不建议使用,因为这会增大服务器的负载。在工作环境中推荐用类似这样的格式H/5 * * * *,表示每5分钟,Jenkins会按Job名字的Hash来分散Poll(轮询)该Job的SCM,已达到负载均衡的目的
  • 在Build框中,向Root POM输入框中填写pom文件的位置mobilebanking/pom.xml,向Goals and options框中填写Maven的命令参数clean test来运行单元测试
  • 点击页面左下角的“Save”按钮来保存

让COMMIT Stage单独自动触发

咱们需要试一试COMMIT Stage能否随着代码提交而自动触发单元测试。

  • 在IntelliJ里打开Java应用程序mobilebanking,随便加一行无关紧要的代码,比如重复调用一遍方法checkUsernameAndPassword(username, password);,但前提是单元测试能够运行通过
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard上,观察mobilebanking-commit这个Item;它会在1分钟内被自动触发
git add .
git commit -m "call method checkUsernameAndPassword() twice"

创建流水线的第二个Stage:ACCEPTANCE

这个ACCEPTANCE Stage是用来运行Robot Framework Web UI自动化测试的。

  • 回到Jenkins的首页Dashboard,点击“New Item”链接
  • 在Enter an item name输入框中输入这个item的名字,比如可以叫mobilebanking-acceptance
  • 点击"Freestyle project",然后点击OK按钮,进入配置页面
  • 勾选“Delivery Pipeline configuration”,在下面出现的Stage Name输入框中,填写这个stage的名字,比如叫ACCEPTANCE;在下面的Task Name输入框中,填写这个stage的描述信息,比如叫Run acceptance tests
  • 在Build框中,点击“Add build step”,然后选择“Execute shell”;在随后出现的Command输入框中,输入下面的脚本来运行Robot Framework Web UI自动化测试
    robot /<完整路径……>/robot-framework-demo/WebDemo/login_tests
  • 点击“Save”保存

将两个Stage串起来

现在来把第二个Stage ACCEPTANCE挂到第一个Stage COMMIT之后,使得第一个Stage正常运行结束后,能自动触发第二个Stage继续运行。

  • 回到Jenkins的首页Dashboard,点击mobilebanking-commit进入这个Item的页面,然后点击左边的Configure,在页面底部的Post-build Actions框中,点击Add post-build action,选择Trigger parameterized build on other projects,在Projects to build输入框中输入mobilebanking-acceptance,在Trigger when build is输入框中选择“Stable”,勾选Trigger build without parameters,点击Save保存
  • 在IntelliJ里mobilebanking这个Java应用程序中,将上述重复调用的方法checkUsernameAndPassword(username, password);删掉
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard上,观察mobilebanking-commitmobilebanking-acceptance这两个Item;它们先后会在1分钟内被自动触发
git add .
git commit -m "delete duplicated method checkUsernameAndPassword()"

创建一个视图来可视化Deployment Pipeline

用视图将上面两个Stage串起来的配置进行可视化,以便方便地看到谁的代码提交在哪个环节引起了什么质量问题

  • 回到Jenkins的首页Dashboard,点击All右边的"+"号,在View Name输入框中输入一个视图的名字,比如叫Deployment Pipeline;再选择"Delivery Pipeline View",点击OK;
  • 在配置页面中勾选“Show commit messages”来显示代码提交描述信息,勾选“Show test results”来显示单元测试运行情况信息
  • 在Pipelines框中,Component的Name输入框中输入该视图的名字,比如叫“Deployment Pipeline”,在Initial Job输入框中选择mobilebanking-commit来作为初始运行的Stage;点击OK保存

让视图可视化一次代码提交

现在用上面创建的Deployment Pipeline视图,来可视化一次代码提交

  • 在IntelliJ里打开Java应用程序mobilebanking,增加一行代码来重复调用一遍方法checkUsernameAndPassword(username, password);
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard的Deployment Pipeline视图中,观察整个视图;它会在1分钟内被自动触发;另外如果把浏览器调整到仅占据屏幕的一半,那么在运行ACCEPTANCE Stage时,会在屏幕的另一半看到运行Web UI自动化测试的界面
git add .
git commit -m "call method checkUsernameAndPassword() twice again"

让代码编译失败一次

让代码编译失败一次,看看流水线有什么变化。

  • 在IntelliJ里打开Java应用程序mobilebanking,增加一行代码来调用没有创建出来的方法,比如调用方法abc();
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard的Deployment Pipeline视图中,观察整个视图;它会在1分钟内被自动触发,COMMIT变红,如下图所示;
git add .
git commit -m "call method abc()"
Screen Shot 2017-03-11 at 5.35.33 PM.png

让单元测试运行失败一次

让单元测试运行失败一次,看看流水线有什么变化。

  • 在IntelliJ里打开Java应用程序mobilebanking,删除刚才的代码abc();;然后让方法loginWithUsernameAndPassword()返回false,使得单元测试失败
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard的Deployment Pipeline视图中,观察整个视图;它会在1分钟内被自动触发,COMMIT变黄,如下图所示;
git add .
git commit -m "make unit test failed"
Screen Shot 2017-03-11 at 5.43.36 PM.png

让Web UI测试运行失败一次

让Web UI测试运行失败一次,看看流水线有什么变化。

  • 在IntelliJ里打开Java应用程序mobilebanking,让方法loginWithUsernameAndPassword()返回true,使得单元测试能成功
  • 在PyCharm里面打开Python项目robotframework-webdemo,将gherkin_login.robot测试文件中的welcome page should be open改为运行失败,具体改法是将resource.robot文件中的Title Should Be Welcome Page一行,改为Title Should Be Welcome Page 1
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard的Deployment Pipeline视图中,观察整个视图;它会在1分钟内被自动触发,ACCEPTANCE变红,如下图所示;
git add .
git commit -m "make web ui test failed"
Screen Shot 2017-03-11 at 6.29.18 PM.png

让整个流水线成功运行一次

  • 在PyCharm里面打开Python项目robotframework-webdemo,将resource.robot文件中的Title Should Be Welcome Page 1一行,改回Title Should Be Welcome Page
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard的Deployment Pipeline视图中,观察整个视图;它会在1分钟内被自动触发,整个流水线会变绿,如下图所示;
git add .
git commit -m "make web ui test passed"
Screen Shot 2017-03-11 at 6.36.38 PM.png

10行代码搞定“CI搭建兽”的全部手工工作

下面看看如何用“流水线即代码”的实践,用10行Groovy代码搞定“CI搭建兽”的全部手工工作。而这10行代码都放到一个名为Jenkinsfile的纯文本文件中,下面会配置Jenkins,让它运行这个文件的Groovy脚本和配置语句。

先在Jenkins的Web UI里面定义一个流水线

  • 在Jenkins首页点击“New Item”链接
  • 在Enter an item name输入框中输入这个item的名字,比如可以叫pipeline-as-code
  • 点击"Pipeline",表示要创建一个流水线,然后点击OK按钮,进入配置页面
  • 在Build Triggers框中勾选"Poll SCM",然后在下面的"Schedule"输入框中输入* * * * *,这和前面配置COMMIT Stage一样,都表示每分钟Jenkins会查看是否有代码提交进而触发流水线
  • 在Pipeline框中的Definition选择框中,选择"Pipeline script from SCM",表示Jenkins会从版本控制系统来读取Jenkinsfile;
  • 在SCM选择框中选择"Git",并在下面的Repository URL输入框中填写`file://<完整路径……>/jenkins-mobile-banking,来指定Jenkinsfile所在的版本控制系统
  • 最后在最下方的Script Path输入框中,填写mobilebanking/Jenkinsfile,来指定Jenkinsfile的确切位置,点击"Save"保存

在Jenkinsfile里面编写Groovy脚本来定义流水线

  • 在Java程序所在的mobilebanking文件夹中,用IntelliJ创建一个名为Jenkinsfile的纯文本文件,并在该文件中插入以下Groovy代码
node {
    stage('COMMIT') {
        echo 'The COMMIT stage'
        sh 'mvn -f <full path>/jenkins-mobile-banking/mobilebanking/pom.xml clean test'
    }
    stage('ACCEPTANCE') {
        echo 'The ACCEPTANCE stage'
        sh 'robot <full path>/jenkins-mobile-banking/robotframework-webdemo/login_tests'
    }
}

这里,Jenkins一旦见到了node语句,就要为这个流水线分配executor和workspace,所以如果没有node语句,流水线就不会被执行。

stage语句指定了Stage;echo语句用来在console上打印一句话,方便查看运行结果;sh语句指定了要在Unix/Linux机器上运行一句脚本,如果是在Windows机器上,则要用bat语句。

在COMMIT Stage里面的sh语句,执行了maven命令,来运行单元测试,其中mvn命令指定了pom.xml文件的位置;在ACCEPTANCE Stage里面的sh语句,执行了Robot Framework的Web UI 自动化测试。

运行一下流水线

  • 在运行pipeline-as-code流水线前,需要把前面“CI搭建兽”搭建的mobilebanking-commit中Poll SCM里面的* * * * *改为H/5 * * * *,来让这个Job每5分钟执行一次,从而当有代码提交时,不会与后面配置的pipeline-as-code流水线同时执行,以便于单独观察流水线
  • 在命令行中用git命令来提交代码,然后立即在Jenkins首页Dashboard中点击"pipeline-as-code",来观察这个流水线的视图;它会在1分钟内被自动触发,流水线会变绿,如下图所示;如果把浏览器缩小到屏幕的一半,那么就能看到屏幕另一半Web UI自动化测试在打开另一个浏览器来运行;
git add .
git commit -m "update Jenkinsfile"
Screen Shot 2017-03-12 at 11.35.52 AM.png
  • 再过几分钟,“CI搭建兽”搭建的mobilebanking-commit也会被触发执行

部署流水线与单件流

单件流指的是,正在制作的产品的各个模块,能从最初的对其增加价值的加工步骤,直接传递到下一个增值加工步骤进行加工,并最终被传递到客户手中,在这个过程中,各个步骤之间没有发生等待或者排队的现象(参见《丰田套路》)。

而如果在各个步骤的传递过程中发生了等待或排队,那就等同于建立了库存。软件开发中常见的库存包括排队等候开发的需求、排队等候测试的代码、排队等待修复的缺陷、排队等待上线的产品特性、甚至Ticket和邮件系统;

隐藏很深的库存可以由诸如那些有固定期限(比如每月一次)的“用户验收测试”的流程来造成——月初几天就开发测试完毕的产品特性必须要被存放近一个月,等到月底“用户验收测试”后才能继续往下游走。软件开发中的上述库存就是让项目延期的最大原因。

企业如果能做到单件流,那么就相当于消灭了库存,让价值在不同环节之间流动得最快,进而实现了全局优化。

这次操练所搭建的部署流水线,可以作为一个工具来可视化软件开发从代码提交之后的价值流。如果代码在各个Stage之间都无须排队且自动化地流动,那么就实现了Continuous Deployment,也就是在代码提交之后实现了软件开发最高效的单件流。


操练成就匠艺
全栈软件开发者的技术操练社区:bjdp.org北京设计模式学习组
QQ群号:235913915,微信订阅号:bjdp_org,网站:www.bjdp.org

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • <<互联网敏捷DevOps和自动化之5.持续集成>>持续集成的价值是什么?对于开发和测试人员又意味着什么呢?1.1...
    燕京博士阅读 2,700评论 0 5
  • 2016年11月份的技术雷达中给出了一个简明的定义:流水线即代码 (Pipeline as Code) 通过编码而...
    lambeta阅读 904评论 0 4
  • 文/鄢倩 2016年11月份的技术雷达中给出了一个简明的定义:流水线即代码(Pipeline as Code)通过...
    ThoughtWorks阅读 1,238评论 3 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 1.一旦安装APP程序,启动页和图片都会先加载进去,如果旧版本没设置启动页的话,安装新版本即时设置成功了也不会显示...
    赤焰军少帅林殊阅读 151评论 0 0