前面两篇教程我们陆续介绍了基于 Github 代码仓库集成CircleCI 和Travis CI 实现 Laravel 项目的持续集成,今天我们继续介绍如何通过 Jenkins 实现类似的自动构建和测试。
相较于前两种持续集成系统,Jenkins 没有在 Github Marketable 上提供第三方应用,我们日常使用的话通常需要自己在独立服务器上安装并进行运维,你可以参考 官方文档 进行下载安装,然后创建一个 Pipeline 构建任务,最后在 Github 仓库的 Webhooks 页面添加相应的回调 URL,或者你还可以在本地项目根目录下 .git/hooks
里面定义的事件触发执行相应的 Jenkins 回调 URL(这种情况下你甚至可以在本地安装 Jenkins,比如 laradock
集成环境中就包含了 Jenkins),通过这个流程当然可以实现通用的持续集成流程,但是这一波操作对新手来说不够友好,而且比较重量级,另外,Jenkins 的插件中心在国内网络环境访问起来有些吃力,所以学院君今天的示例将基于国内的 Coding 平台 提供的持续交付整体解决方案来进行演示,这套解决方案中当然包含了代码托管和持续集成的部分,而且刚好它的持续集成解决方案是基于 Jenkins 的。在该方案下,Coding 平台为我们封装了 Jenkins 的安装、维护和触发回调,我们只需要编写 Jenkins 的构建任务即可。
首先打开 Coding 首页 ,Coding 提供了一站式 DevOps 解决方案,从需求到开发、测试、缺陷管理、项目管理、代码托管、持续集成、部署上线都可以通过这个一站式解决方案来完成,而且这个服务对五人以下小团队免费,推荐大家试试:
你可以浏览下首页介绍和产品里面的产品列表对 Coding 平台有一个大致的了解,然后我们进入正题,如果你还没有注册过 Coding 平台,可以点击「免费体验」按钮开始创建团队和用户(已注册跳过):
输入团队名称和专属域名,然后点击「下一步」:
在上面这个页面中,输入团队管理者信息并完成注册,注册完成后,页面就会跳转到一个示例项目页面,通过这个示例项目,我们可以快速了解 Coding DevOps 解决方案的所有功能:
继续后续功能之前,先到注册邮箱收件箱中激活 Coding 账户,否则后续提交代码到仓库会提示要激活账号。
接下来,我们点击页面右上角的「+」图标为待办任务应用创建一个新项目,在创建项目页面,你还可以选择导入已有项目:
不过,目前该功能只支持 Coding 个人版和 Gitlab 项目,Github 项目还不支持,因此我们需要创建一个新项目:
创建新项目流程和 Github 差不多,都需要指定项目信息和项目地址,以及描述信息和初始化文件,所不同的时由于 Coding 更关注的是项目的整体 DevOps 和日常管理,所以多出了项目时间和项目成员选项,你可以根据需要进行设置。最后点击「新建项目」按钮,页面就跳转到新建项目的管理页面(和之前示例项目一样):
在这里,由于代码仓库还没有提交任何代码,所以可以看看在编写代码前可以做的事情,比如迭代管理、需求管理、工作管理等,代码、持续集成、部署管理则依赖开发代码提交后才能预览和管理,你还可以通过 Wiki 为项目编写文档,通过统计查看代码、测试、缺陷统计图表,最后还可以通过设置进行更多的管理功能,具体操作和使用都很简单,你可以自行去研究。
接下来,我们将之前编写的待办任务项目代码关联到 Coding 仓库,由于之前项目已经关联到 Github 仓库,所以我们拉一份新的项目代码,然后将其关联到新创建的 Coding 仓库,具体操作步骤如下:
git clone https://github.com/nonfu/todoapp todoapp2 cd todoapp2 rm -rf .git git init git remote add origin https://e.coding.net/laravel/todoapp.git git add . git commit -m 'first commit' git push --set-upstream origin master
基本上也都是一些 Git 命令操作,首次 push 代码后,就可以在项目管理页面点击代码->代码浏览看到刚刚提交上来的代码了:
有了代码之后,下面我们来编写持续集成构建任务,点击「持续集成」菜单,进入如下页面:
在这里,我们给构建任务取个名字,然后定义构建触发的时间节点以及触发的方式,一般选则在推送分支的时候自动触发,关于执行方式,对于 PHP 项目来说,推荐使用「云服务器模式」,然后通过引入 Docker 镜像构建测试环境,因为 Coding 默认的常规模式更偏向于 Java 项目,对 PHP 项目来说并不够友好。
然后我们保存进入下一步,配置集成过程,由于学院君前面提到过,Coding 是基于 Jenkins 做持续集成的,所以需要配置相应的 Pipeline 来对项目进行构建、测试、部署,如果你对 Jenkins 不太了解,可以点击页面上提供的提示链接查看,然后我们根据需要选择一个模板来编写 Jenkinsfile,比如「简易模板」:
这样,就进入了 Jenkinsfile 文件编辑页面,我们可以根据自己的构建需要对默认模板进行修改,比如我这里最终的 Jenkinsfile 版本如下:
node { stage("检出") { sh 'ci-init' checkout( [$class: 'GitSCM', branches: [[name: env.GIT_BUILD_REF]], userRemoteConfigs: [[url: env.GIT_REPO_URL]]] ) sh 'pwd' } docker.image('mysql:5.7').withRun('-e "MYSQL_ALLOW_EMPTY_PASSWORD=true"') { c -> docker.image('mysql:5.7').inside("--link ${c.id}:mysqldb") { /* Wait until mysql service is up */ sh 'while ! mysqladmin ping -hmysqldb --silent; do sleep 1; done' } docker.image('circleci/php:7.1-node-browsers').inside("--link ${c.id}:mysqldb") { /* 以下构建步骤需要依赖 MySQL,MySQL 主机名是 mysqldb */ stage("环境初始化") { echo "环境初始化中..." sh 'apt-get update' sh 'apt-get install -y google-chrome-stable' sh 'apt install -y mysql-client' sh 'mysql -h mysqldb -u root -e "create database todoapp;"' sh 'docker-php-ext-install zip' sh 'docker-php-ext-install pdo_mysql' echo "环境初始化完成." } stage("环境检测") { echo "环境检测中..." sh 'php --version' sh 'composer --version' sh 'npm --version' sh 'mysql --version' echo "环境检测完成." } stage("构建") { echo "构建中..." sh 'composer self-update' sh 'mv .env.testing .env' sh 'composer install -n --ignore-platform-reqs' sh 'npm install' sh 'npm run production' sh 'php artisan key:generate' sh 'php artisan migrate' sh 'php artisan passport:install' sh 'php artisan serve &' echo "构建完成." } stage("测试") { echo "单元测试中..." sh 'vendor/bin/phpunit' sh 'php artisan dusk' echo "单元测试完成." } stage("部署") { echo "部署中..." // sh 'envoy run deploy' echo "部署完成" } } } }
Coding 提供的持续集成功能有多种执行方式,具体可以参考 官方文档 ,我这里选择的是云服务器模式下的 使用预装 Docker 构建 ,其实也就是 Jenkins 里面 通过 Docker 进行构建 ,该文件保存后会推送到仓库项目根目录,后续当我们推送代码到仓库时,Coding 就会根据这个 Jenkinsfile 文件对项目进行构建。
下面我们简单看下这个构建任务做了哪些工作:
mysqldb
,以便在嵌套环境中通过它与 MySQL 服务器连接(这种嵌套在叫做 sidebar pattern ); docker.image(...).inside(...)
用于等待 MySQL 服务可用; docker.image('circleci/php:7.1-node-browsers').inside(...)
中定义了正式的构建逻辑,这里面的逻辑需要 MySQL 服务可用后才能执行; stage
进行区分,每个 stage
代表一个独立的构建步骤,比如「环境初始化」中我们对数据库进行初始化并安装了相应的 PHP 扩展,然后在「环境检测」中对必须的软件进行检测; phpunit
运行 HTTP 测试和 php artisan dusk
运行浏览器测试; Jenkinsfile 编辑好保存后,Coding 会将其推送到代码仓库,此时就会触发第一个构建,在构建记录详情页中,可以看到构建的每一个步骤及相应的日志,如果构建失败,则终止后续脚本执行:
你可以在相应的日志中看到构建失败的原因,点开即可:
这里提示的是 Chrome 版本不对,需要将 Dusk 扩展包自带的 chromedriver-linux
进行升级,以便支持最新版本的 Chrome(当前是 74)。我们可以从 ChromeDriver 官网 下载针对 Linux 系统的最新版本 chromedriver
,将下载文件在本地解压,然后将 chromedriver
文件拷贝到待办任务项目根目录 todoapp2
下,修改 Jenkinsfile
文件测试步骤脚本如下(如果本地没有该文件,可以通过 git pull
拉取):
stage("测试") { echo "单元测试中..." sh 'vendor/bin/phpunit' sh 'cp -r ./chromedriver ./vendor/laravel/dusk/bin/chromedriver-linux' sh 'php artisan dusk' echo "单元测试完成." }
即通过针对 Linux 系统最新版本的 chromedriver
覆盖系统自带的 chromedriver-linux
,然后我们将上述更改提交并推送到代码仓库(以上操作也可以在构建任务中实现,但耗时较长,还是本地推送更改更快),此时 Coding 平台会自动触发新一轮的构建。这一次构建、测试成功:
这样,我们就可以将开发分支代码合并到主干了,从而完成了一次持续集成。
关于 Coding + Jenkins 实现 Laravel 项目的持续集成我们就简单介绍到这里,Coding 平台提供的这个整体 DevOps 解决方案,对小团队或者中大型公司的持续交付团队来说,都可以一试,更多功能的使用请参考 官方文档 并结合自己的实践去探索。