持续集成作为敏捷开发重要的一步,其目的在于让产品快速迭代的同时,尽可能保持高质量。每一次代码更新,都要通过自动化测试来检测代码和功能的正确性,只有通过自动测试的代码才能进行后续的交付和部署。本文主要介绍如何将时下最流行的持续集成工具之一的 Jenkins 结合阿里云容器服务,实现自动测试和镜像构建推送。
以下内容演示如何通过阿里云容器服务 Jenkins 实现自动测试和 Docker 镜像构建,实现高质量的持续集成。
背景信息
每次代码提交到 GitHub 上的 nodejs 的项目后,阿里云容器服务 Jenkins 都会自动触发单元测试,测试通过则继续镜像构建及推送到目标镜像仓库中,最后邮件通知结果。
大致流程如下图所示:
slave-nodejs 用于进行单元测试,构建镜像和推送镜像的 slave 节点。
Jenkins 相关介绍
Jenkins 是基于 Java 开发的一种开源持续集成工具,监控并触发持续重复的工作,具有开源,支持多平台和插件扩展,安装简单,界面化管理等特点。Jenkins 使用 job 来描述每一步工作。节点是用来执行项目的环境。Master 节点是 Jenkins job 的默认执行环境,也是 Jenkins 应用本身的安装环境。
master/slave
master/slave 相当于 server 和 agent 的概念。master 提供 web 接口让用户来管理 job 和 slave,job 可以运行在 master 本机或者被分配到 slave 上运行。一个 master 可以关联多个 slave 用来为不同的 job 或相同的 job 的不同配置来服务。
可以通过配置多个 slave 为不同项目准备单独的测试和构建环境。
[backcolor=transparent]注意:本文中提到的 Jenkins job 和项目均指的是 Jenkins 一个构建单元,执行单元。
步骤 1 使用容器服务部署 Jenkins 应用和 slave 节点
不同应用构建、测试所需要的依赖不同,最佳实践是使用包含相应的运行时依赖和工具的不同 Slave 容器执行测试和构建。通过阿里云容器服务提供的针对 Python、Node.js、Go 等不同环境的 Slave 镜像以及示例模板,用户可以简单快速地生成 Jenkins 应用以及各种 slave 节点,在 Jenkins 应用中配置节点信息,然后在构建项目中指定执行节点,从而实现整个持续集成流程。
[backcolor=transparent]注意:有关阿里云容器服务提供的开发 slave 节点镜像,参见
https://github.com/AliyunContainerService/jenkins-slaves。
1.1 创建 Jenkins 编排模版。
新建模版,以如下内容为基础,创建编排。
阿里云容器服务 Jenkins master 支持标签 1.651.3、2.19.2、2.32.2。
[backcolor=transparent]注意:有关如何创建编排模板,参见
创建编排模板。
- [backcolor=transparent]jenkins[backcolor=transparent]:
- [backcolor=transparent] image[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'registry.aliyuncs.com/acs-sample/jenkins:1.651.3'
- [backcolor=transparent] volumes[backcolor=transparent]:
- [backcolor=transparent] [backcolor=transparent]-[backcolor=transparent] [backcolor=transparent]/var/[backcolor=transparent]lib[backcolor=transparent]/[backcolor=transparent]docker[backcolor=transparent]/[backcolor=transparent]jenkins[backcolor=transparent]:[backcolor=transparent]/var/[backcolor=transparent]jenkins_home
- [backcolor=transparent] restart[backcolor=transparent]:[backcolor=transparent] always
- [backcolor=transparent] labels[backcolor=transparent]:
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]scale[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'1'
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]probe[backcolor=transparent].[backcolor=transparent]url[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'tcp://container:8080'
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]probe[backcolor=transparent].[backcolor=transparent]initial_delay_seconds[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'10'
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]routing[backcolor=transparent].[backcolor=transparent]port_8080[backcolor=transparent]:[backcolor=transparent] jenkins
- [backcolor=transparent] links[backcolor=transparent]:
- [backcolor=transparent] [backcolor=transparent]-[backcolor=transparent] slave[backcolor=transparent]-[backcolor=transparent]nodejs
- [backcolor=transparent]slave[backcolor=transparent]-[backcolor=transparent]nodejs[backcolor=transparent]:
- [backcolor=transparent] image[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'registry.aliyuncs.com/acs-sample/jenkins-slave-dind-nodejs'
- [backcolor=transparent] volumes[backcolor=transparent]:
- [backcolor=transparent] [backcolor=transparent]-[backcolor=transparent] [backcolor=transparent]/var/[backcolor=transparent]run[backcolor=transparent]/[backcolor=transparent]docker[backcolor=transparent].[backcolor=transparent]sock[backcolor=transparent]:[backcolor=transparent]/var/[backcolor=transparent]run[backcolor=transparent]/[backcolor=transparent]docker[backcolor=transparent].[backcolor=transparent]sock
- [backcolor=transparent] restart[backcolor=transparent]:[backcolor=transparent] always
- [backcolor=transparent] labels[backcolor=transparent]:
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]scale[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'1'
1.2 使用模板创建 Jenkins 应用和 slave 节点。
使用上边新建的编排模板或者直接使用阿里云容器服务提供的 Jenkins 示例模版创建 Jenkins 应用和 slave 节点。
[backcolor=transparent]注意:有关如何使用编排模板创建应用,参见
创建应用。
创建成功后,Jenkins 应用和 slave 节点显示在服务列表中。
打开容器服务提供的访问端点,就可以使用刚刚部署的 Jenkins 应用。
步骤 2 实现自动测试及自动构建推送镜像
2.1 将 slave 容器配置成 Jenkins 应用的 slave 节点。
打开 Jenkins 应用,进入系统设置界面,选择管理节点,新建节点,配置相应参数。如下图所示。
[backcolor=transparent]注意:
2.2 创建项目实现自动化测试。
- 新建 Item,选择构建一个自由风格的软件项目。
- 填写项目名称,并选择项目运行节点。此示例中填写上述准备的 slave-nodejs-ut 节点。
- 配置源码管理和代码分支。此示例中源代码使用 GitHub 管理。
- 配置构建触发器,此示例采用结合 GitHub Webhooks & services 实现自动触发项目执行。
- 在 GitHub 中添加 Jenkins 的 service hook,完成自动触发实现。
在 GitHub 项目主页单击 [backcolor=transparent]Settings,单击左侧菜单栏中的 [backcolor=transparent]Webhooks & services,单击 [backcolor=transparent]Add Service,在下拉框中选择 [backcolor=transparent]Jenkins(Git plugin)。在 [backcolor=transparent]Jenkins hook url 对话框中填写${Jenkins IP}/github-webhook/,例如:[backcolor=transparent]http[backcolor=transparent]:[backcolor=transparent]//jenkins.cd****************.cn-beijing.alicontainer.com/github-webhook/
增加 Execute shell 类型的构建步骤,编写 shell 脚本执行测试。
本示例中的命令如下所示:
- [backcolor=transparent] pwd
- [backcolor=transparent] ls
- [backcolor=transparent] cd chapter2
- [backcolor=transparent] npm test
[backcolor=transparent]SVN 代码源示例:
在源码管理模块选择 [backcolor=transparent]Subversion。[backcolor=transparent]Repository URL 中填入 SVN repository 的地址。(如果 Jenkins master 时区和 SVN 服务器时区不一致,请在 repository 地址末尾添加 @HEAD)[backcolor=transparent]Credentials 中添加 SVN 服务器的用户名和密码。
配置构建触发器,此示例采用 Post-commit hook 实现自动触发项目执行。在 [backcolor=transparent]身份验证令牌 中填写您设置的 token。
登录 SVN 服务器,在代码 repository(svn-java-demo)的 hooks 文件目录下创建 post-commit 文件。
- [backcolor=transparent]cd [backcolor=transparent]/[backcolor=transparent]home[backcolor=transparent]/[backcolor=transparent]svn[backcolor=transparent]/[backcolor=transparent]svn[backcolor=transparent]-[backcolor=transparent]java[backcolor=transparent]-[backcolor=transparent]demo[backcolor=transparent]/[backcolor=transparent]hooks
- [backcolor=transparent]cp post[backcolor=transparent]-[backcolor=transparent]commit[backcolor=transparent].[backcolor=transparent]tmpl post[backcolor=transparent]-[backcolor=transparent]commit
- [backcolor=transparent]chmod [backcolor=transparent]755[backcolor=transparent] post[backcolor=transparent]-[backcolor=transparent]commit
在 post-commit 文件中添加 curl -u ${Jenkins_account}:${password} ${Jenkins_url}/job/svn/build?token=${token} 命令。例如:curl -u test:test
http://127.0.0.1:8080/jenkins/job/svn/build?token=qinyujia 。
2.3 创建项目实现自动构建,推送镜像。
- 新建 Item,选择构建一个自由风格的软件项目。
- 填写项目名称,并选择项目运行节点。此示例中填写上述准备的 slave-nodejs-ut 节点。
- 配置源码管理和代码分支。此示例中源代码使用 GitHub 管理。
- 添加如下触发器,设置只有在单元测试成功之后才执行自动构建镜像。
- 编写构建镜像和推送镜像的 shell 脚本。
本示例的命令如下所示:[backcolor=transparent] cd chapter2 - [backcolor=transparent] sudo docker build [backcolor=transparent]-[backcolor=transparent]t registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]qinyujia[backcolor=transparent]-[backcolor=transparent]test[backcolor=transparent]/[backcolor=transparent]nodejs[backcolor=transparent]-[backcolor=transparent]demo [backcolor=transparent].
- [backcolor=transparent] sudo docker login [backcolor=transparent]-[backcolor=transparent]u $[backcolor=transparent]{[backcolor=transparent]yourAccount[backcolor=transparent]}[backcolor=transparent] [backcolor=transparent]-[backcolor=transparent]p $[backcolor=transparent]{[backcolor=transparent]yourPassword[backcolor=transparent]}[backcolor=transparent] registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com
- [backcolor=transparent] sudo docker push registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]qinyujia[backcolor=transparent]-[backcolor=transparent]test[backcolor=transparent]/[backcolor=transparent]nodejs[backcolor=transparent]-[backcolor=transparent]demo
步骤 3 自动重新部署应用
3.1 首次部署应用
使用编排模板,将 2.3 中创建的镜像部署到容器服务中,创建 [backcolor=transparent]nodejs-demo 应用。
示例如下所示:
- [backcolor=transparent]express[backcolor=transparent]:
- [backcolor=transparent]image[backcolor=transparent]:[backcolor=transparent] [backcolor=transparent]'registry.aliyuncs.com/qinyujia-test/nodejs-demo'
- [backcolor=transparent]expose[backcolor=transparent]:
- [backcolor=transparent] [backcolor=transparent]-[backcolor=transparent] [backcolor=transparent]'22'
- [backcolor=transparent] [backcolor=transparent]-[backcolor=transparent] [backcolor=transparent]'3000'
- [backcolor=transparent]restart[backcolor=transparent]:[backcolor=transparent] always
- [backcolor=transparent]labels[backcolor=transparent]:
- [backcolor=transparent] aliyun[backcolor=transparent].[backcolor=transparent]routing[backcolor=transparent].[backcolor=transparent]port_3000[backcolor=transparent]:[backcolor=transparent] express
3.2 自动重新部署
- 选择刚刚创建的应用 [backcolor=transparent]nodejs-demo,创建触发器。
[backcolor=transparent]注意:有关如何创建触发器,参见
触发器。
- 在2.3 中的 shell 脚本中添加一行,地址即为上文创建的触发器给出的触发器链接。[backcolor=transparent] curl [backcolor=transparent]‘[backcolor=transparent]https[backcolor=transparent]:[backcolor=transparent]//cs.console.aliyun.com/hook/trigger?triggerUrl=***==&secret=***’
把 2.3 示例中的命令改为:
- [backcolor=transparent] cd chapter2
- [backcolor=transparent] sudo docker build [backcolor=transparent]-[backcolor=transparent]t registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]qinyujia[backcolor=transparent]-[backcolor=transparent]test[backcolor=transparent]/[backcolor=transparent]nodejs[backcolor=transparent]-[backcolor=transparent]demo [backcolor=transparent].
- [backcolor=transparent] sudo docker login [backcolor=transparent]-[backcolor=transparent]u $[backcolor=transparent]{[backcolor=transparent]yourAccount[backcolor=transparent]}[backcolor=transparent] [backcolor=transparent]-[backcolor=transparent]p $[backcolor=transparent]{[backcolor=transparent]yourPassword[backcolor=transparent]}[backcolor=transparent] registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com
- [backcolor=transparent] sudo docker push registry[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]qinyujia[backcolor=transparent]-[backcolor=transparent]test[backcolor=transparent]/[backcolor=transparent]nodejs[backcolor=transparent]-[backcolor=transparent]demo
- [backcolor=transparent] curl [backcolor=transparent]‘[backcolor=transparent]https[backcolor=transparent]:[backcolor=transparent]//cs.console.aliyun.com/hook/trigger?triggerUrl=***==&secret=***’
到此,镜像推送之后,Jenkins 会自动触发重新部署 nodejs-demo 应用。
步骤 4 配置邮件推送结果
如果希望单元测试或者镜像构建的结果能够通过邮件推送给相关开发人员或者项目执行发起者。可以通过如下配置来实现。
- 在 Jenkins 主页,选择系统管理,系统设置,配置 Jenkins 系统管理员邮箱。
- 安装 Extended Email Notification plugin,配置 SMTP server 等相关信息,并设置默认邮件接收人列表。如下图所示。
以上是 Jenkins 应用系统参数设置,下面是为需要用邮件推送结果的 Jenkins 项目进行相关配置。 - 在 Jenkins 项目中添加构建后操作步骤。选择 Editable Email Notification 类型,填写邮件接收人列表。
- 添加邮件发送触发器。