OpenStack 是当下炽手可热的 IaaS 开源云计算项目,使用 OpenStack 可满足企业各种云服务需求,如私有云、混合云或公有云。通过本系列教程的学习,即使是一个初入云计算的行业者也能迅速熟悉和掌握 OpenStack 的相关技术,提高职业竞争力,成为一名复合型人才。
本系列教程,分为四部分,共计15篇文章。读者可以从中汲取到完整的项目经验,从菜鸟到精通,这个达人课帮您实现。
第一部分(1-4篇):主要讲解初学者如何参与 OpenStack 社区,进行有效的沟通交流,以及如何提交 Bug 和 Patch,快速提升个人参与开源社区的能力。
第二部分(5篇):主要讲解当下主流的 OpenStack 生产环境级的部署实施。
第三部分(6-14篇):主要讲解 OpenStack 全方位,不同维度和层次的测试体系。涵盖了性能测试、存储测试、功能测试、单元测试以及Dashboard 自动化测试和开发自动化测试框架等内容。
第四部分(15篇):主要讲解如何使用 Harbor 镜像仓库管理 OpenStack Docker 镜像等。
徐超,某互联网公司任云计算工程师。技术出身,三年多 OpenStack 运维开发经验,熟悉 Kubernetes、Docker、Ceph 存储和 CI/CD。2017年初,出版《OpenStack 最佳实践——测试与 CI/CD》一书。
知其然,知其所以然。相较于DevOps而言,CI/CD是一个相对具象的概念。在 IT 企业中,CI/CD的应用愈加广泛,成为推动软件研发活动的重要基础设施服务,同时推动 DevOps 模式的实际落地。
在实践 CI/CD 相关内容之前,我们有必要先认识下什么是 CI/CD。
一般传统或者狭义、普遍的 CI/CD,是指持续集成(Continuous Integration,CI)和持续交付(Continuous Delivery,CD)。而更加广义、全面的理解,是指持续集成(Continuous Integration,CI)、持续测试(Continuous Testing,CT)、持续交付(Continuous Delivery,CD)和持续部署(Continuous Deployment,CD)四个方面。通常,一个软件开发的流水线如下图所示。
随着敏捷开发的发展,持续集成在软件项目活动中也日益成为主流。顾名思义,持续集成是指每日频繁地(比如一天多次)将代码集成到主干分支中。强调通过集成和测试的速度,快速给出一个集成的结果(是失败还是成功),在代码集成之前,必须先通过自动化测试验证,只要有一个测试用例失败,就不能集成。
Martin Fowler 说过,“持续集成并不能消除Bug,而是让它们非常容易被发现和改正”。这也正是持续集成的真谛所在。
敏捷开发的核心是指整个软件开发活动被划分成一系列短的迭代过程,每个迭代完成一定数量的功能,迭代周期应该尽量短。在软件开发需求已经确定的情况下,迭代应该由测试驱动开发(TDD)和集成反馈来驱动。只有这样,才能为质量持续改进奠定一个良好的基础。
持续集成是和单元测试结合在一起的,也就意味着,持续集成和单元测试需要并行工作。持续集成一般由代码每次 git push/review 触发。先签入代码就先看到构建结果,后签入,则要排在后面。这就要求构建时间不能太长,否则在构建时容易引起混乱,很难知道是谁的代码破坏了集成,导致很难定位问题。
可以说,持续集成是敏捷开发的重要基础环节,没有持续集成,所谓的敏捷开发便失去了赖以生存的土壤,其实施效果也会大打折扣。持续集成是一种软件开发实践,团队成员频繁集成他们开发的代码,每次集成都会经过自动构建——自动测试的验证,以尽快发现集成错误。使用这种方法可以显著减少集成引起的问题,并加快团队合作开发软件的速度。
(1)持续集成过程
持续集成的工作阶段比较明确,主要有三个大的阶段:持续集成准备阶段、持续集成使用阶段和持续集成测试阶段。
持续集成准备阶段的工作主要包括:
持续集成使用阶段的工作主要包括:
持续集成测试阶段的工作主要是,CI 系统根据集成结果进行不同操作,如果成功,则将代码合并到主分支;如果失败,则反馈给开发人员修改重新提交。
从中我们可以看到,持续集成涉及的主要工具类别包括:
(2)持续集成的好处
主要有以下几点:
持续测试作为软件持续集成中的重要组成部分,为软件项目的成功提供了保证软件质量持续改进的重要手段。在持续集成中,更多的是运行小型的单元测试,因此,关于其他测试将在后续章节中阐述。
持续测试是指开发人员提交代码后自动运行相关单元测试,给出测试结果的反馈;如果失败,则会在测试结果的详情页面中输出错误提示。
有了持续测试,我们才能实现真正的测试驱动开发(TDD)。举一个例子,当开发人员向代码评审系统提交了代码后,Jenkins hooks 监听到有代码提交,自动运行单元测试,然后在页面视图上显示测试的结果;如果测试失败,开发人员需要重新修改并再次提交测试,直至成功。
这也需要开发人员在编写功能代码时,同时编写测试代码,这样几乎能够在问题产生之时就将其发现。不经常运行测试通常就不怎么有效,因为从产生缺陷到发现该缺陷相隔时间很长,但持续地(即每一次代码改变时)运行测试能确保快速地发现症结。
持续测试应当输出测试报告,报告是将持续集成的运行情况以适当的形式展现给相关人员的基本方式。报告是持续集成的晴雨表,所以它必须直观、易懂,比如开发人员从错误日志中找到代码出错的位置和原因;QA 测试人员发现测试的覆盖率和执行情况;管理人员从持续集成通过率的趋势中了解到项目的进度和质量。
持续交付和持续部署是两个非常容易混淆的概念。持续交付指的是频繁地将软件的新版本交付给 QA 测试团队或者运营团队,如果评审通过,代码就进入发布、生产阶段。
为了更加符合国内软件行业的实际情况,我在这里将 QA 和测试统称为“QA 测试”。持续交付可以看作是持续集成、持续测试的延续,它强调的是不管怎么更新,软件是随时随地可以交付的。通过严格的自动化测试,可以确保软件开发的质量和进度。因为通过完全的自动化过程把每个变更自动提交到测试环境中,所以当功能开发完成时,就有信心只需要点击一次按钮就能保证发布和部署应用的质量。
(1)选择持续交付工具集
在没有制定出工作流程时,便考虑选择持续交付工具集,是最不重要的决策。实际上,在设计好工作流程和业务流程之后再选择相匹配的工具集即可。考虑到满足实际业务和工作流程的情况,开发一些诸如 Shell、Python 等脚本程序是非常理性的做法。
更重要的是,无论是 CI 还是 CT、CD 等,都可以使用众多的开源工具,这样做没有被锁定的风险,可以自由切换等。
(2)持续交付的角色和方式
产品持续交付的角色应由 QA 测试人员来担任,开发人员也需要参与到产品的某一轮系统测试中,并随时准备 Bug 审查和 Bug 修复。最后,由 QA 测试人员根据具体的产品缺陷、质量情况等做出产品是否适合面向用户交付、发布的决定。
持续交付的目标不是要消灭缺陷,而是要规范开发和测试的流程,从根源上提高软件质量。总之,持续集成、持续测试、持续交付和持续部署的核心就是让不间断的“密集型、高强度、信息及时反馈的持续性改进”成为提高软件产品质量的驱动力。
目前,持续交付的方式一般有:
持续部署是持续交付的后续阶段,也是整个CI/CD环节中的最后一环,指的是软件通过测试后自动部署到生产环境中。持续部署的目标是软件在任何时刻都是可部署的,可进入生产阶段,发布给用户使用。持续部署的前提是能够自动化完成集成、测试和交付等。它与持续交付的区别是,持续交付是将软件部署到线上环境中,使用的是手动方式;而持续部署强调的是自动化。换言之,持续部署是持续交付的更高阶段,所有通过了测试验证的软件都自动部署到生产环境中。如果没有制度的约束或其他条件的影响,团队都应该以持续部署为目标,如下图所示。
DevOps是一种工程文化、理论集,是一个抽象的概念;而其范畴下的 CI/CD 则是它的具体实现和方法,是一种化抽象为形象的工具集、流程图。如果说 DevOps 是云计算,那么 CI/CD 就是计算、存储和网络,OpenStack 则是其具体实现平台。
软件项目的研发有两大难题:一是确定软件的需求,即确定目标;二是确定当前离目标还有多远,即确定剩余的工作量。后者是项目缺少可见性的问题。前者是持续性反馈的问题。比如来自用户需求的反馈、市场变化的反馈、项目研发测试过程的反馈等。
自动化是软件研发测试中的重要方式。持续集成最大的优点就是降低风险,提高项目研发过程的效率和质量,迎合互联网时代信息快速更新的规律。持续集成本身并不能帮助开发工程师和 QA 工程师解决Bug,而是通过不断的测试和反馈来尽早地发现 Bug,问题发现得越早,处理问题的成本就越小,也越容易解决。由于无法证明通过了某次测试的代码永远无缺陷,因此,持续集成中的测试也就显得非常重要,好的测试能够更多、更快地发现当前版本中的错误。
根据持续集成的作业流,代码从提交到生产环境,整个过程分为以下几步。
开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交。
整个 CI 系统配置了代码仓库系统、Jenkins 系统和代码评审系统的触发器,只要提交代码就会运行自动化测试。一般这里的测试有如下几种。
通过第1轮测试后,代码就可以合并进主干分支,推送到私有代码仓库 GitLab 系统中,进行下一阶段的构建了。
从开发人员提交本地代码,到测试通过,代码合并到分支里,提交就算完成了。此时,就需要进行构建进入第2轮测试。所谓构建,指的是将源码转换为可以运行的 Linux 标准软件包,比如安装依赖、生成配置文件等,当然也可以构建成 Docker 镜像。
构建完成后,就要进行第2轮或多轮测试。总之,构建部署在测试之前。
此阶段的测试最全面,投入资源最多,包括系统测试、功能/集成测试、性能测试等都会运行。需要强调的是,每一个更新点都必须测试到。如果测试的覆盖率不高,进入后面的部署和生产阶段后,很可能会出现严重的问题。
通过多轮测试后,当前代码就是一个可以直接部署的稳定版本。将这个版本的所有文件打包存档(比如 Fuel 的 iso,或其他自研产品的 iso、vmdk 乃至 Docker 镜像等),发布到成品库服务器上。这方面的自动化部署工具有 Ansible、Chef、Puppet 等。
一旦当前软件版本发生问题,就要回滚到上一次构建的版本,使用上一次构建并发布的版本。
CI/CD 很好地解决了代码从自动化编译打包、自动化构建部署、自动化测试到快速交付产品4个阶段。为此,需要做到:
构建工作主要产出两个东西:待测的软件包和应用系统(有的只有后者)。这两个产出物有所不同,前者是构建过程与环境无关,而且可重复,因此需要提供如 yum、npm、gem 等软件包服务,让构建号和软件包号建立关联,便于回溯。
通过 IaaS 云或 Docker 容器将 CI/CD 环境以微服务的方式运行,做到开箱即用。CI/CD是软件工程的一个重要实践,可以帮助我们更早地发现问题、解决问题,降低成本,同时大大减少交付、发布过程中的不确定性,提高团队的生产效率。当然,CI/CD 与其他工具和方法也紧密相关。
每日构建(Daily Build)在反应速度上没有持续集成快,它更强调的是通过每天(通常是晚上)自动部署当天开发所累积的代码,并结合每日测试(Daily Test)方法进行自动化测试,用于评估和衡量项目的进度。
持续集成特性决定了不可能在该阶段加入大量的测试,而每日构建则一般是在夜里执行的,那么这时就可以做更多的事情,比如代码质量检查、单元测试、测试覆盖率、集成测试等。每日构建会把当天所有的提交代码都一起做集成,而不像持续集成那样每提交一次代码就做一次集成。持续集成属于增量式构建,而每日构建则是一次完全构建。
每日构建是项目的心跳线。一般而言,通过每日构建我们可以看到项目的进度。比如今天有10个 Bug 的修复代码都提交了,晚上进行自动部署并通过了自动化测试,第二天上班时通过查看邮件我们就可以发现每日构建成功了,那么项目就又往前迈了一大步,开发工作又有了具体的进展。
具体的,每日构建就是在每天晚上自动化部署一个 OpenStack 环境(可以是all-in-one,也可以是 multi-node),然后运行大型或专项测试,比如 API 性能测试、API 接口测试、功能测试、部署测试等。
OpenStack社区贡献内容包括但不限于:
在开始贡献之前,我们先来看看 OpenStack 的代码审查的大体流程,如下图所示。
从 OpenStack 本地代码提交到合并的流程主要如下:
基本步骤如下:
说明:一般情况下,只有当修复某个代码/文档 Bug 或发现有 Bug 时,才需要在Launchpad 上提交 Bug 信息。
在 https://launchpad.net/ 上注册账号,如下图所示。
注册成功后,登录 Launchpad,输入想要提交的 Bug 所属的 OpenStack 项目名称。比如这里的 openstack-manual(OpenStack 文档项目),如下图所示。
在图中,可以看到与该项目相关的 Bug、Blueprints 和项目概述信息等内容。点击“Report a bug”,提交一个 Bug,如下图所示。
紧接着,需要简要描述下该 Bug 的一些关键信息,如下图所示。
填写相应的Bug信息,如下图所示。
如果想要修复这个 Bug,可以将它指定给自己,如下图所示。
注意这个 Bug id 号,届时向 OpenStack 社区提交代码时需要。如此,这就是创建 Launchpad账号和提交 Bug 的流程。如果想要修复这个 Bug,那么继续往下操作。
使用在 Launchpad 上注册的账号,登录 https://review.openstack.org,如下图所示。
配置 Gerrit 公钥认证,将 SSH 的 Public Key 粘贴到此处,如下图所示。
签署 ICLA 协议,如下图所示。
在国内网络的背景下,想要向社区代码评审系统提交代码,需要一点小技巧(VPN 用户可以忽略此步骤)。首先需要登录 review.openstack.org,然后在 Settings -> HTTP Password 中生成一个 HTTP 密码,它应该是一个大小写字母加数字的随机字符串。创建一个 HTTP 协议的用户名和密码,如下图所示。
此时,账号已经创建和配置好,下面即可提交修改后的代码了。
//clone该Bug所属的项目#git clone https://git.openstack.org/openstack/openstack-manuals //格式为bug/bug id# git checkout -b bug/1575714Switched to a new branch 'bug/1575714'//修改Bug文件# vim doc/contributor-guide/source/api-guides.rst//配置git邮件地址和用户名# git config --global user.email [email protected]# git config --global user.name "xxxx"//添加本地文件# git add .//填写提交信息,格式和内容如下# git commit Fix OpenStack/api-site git repo urlCloses-Bug: #1575714//添加远程地址# git remote add gerrit\ssh://[email protected]:29418/openstack/openstack-manuals.git# git remote set-url gerrit\https://http_username:[email protected]/openstack/openstack-manuals.git//提交代码# git reviewYour change was committed before the commit hook was installed.Amending the commit to add a Gerrit change id.remote: Processing changes: new: 1, refs: 1, done remote: remote: New Changes:remote: https://review.openstack.org/310508 Fix openstack/api-site git repo urlremote: To https://xxxx:xxxx @review.openstack.org/openstack/openstack-manuals.git * [new branch] HEAD -> refs/publish/master/bug/1575714
如果需要对之前提交的内容再次进行修改(针对同一个 change-id),则执行如下命令。
# git add .# git commit --amend# git review
向社区提交代码/文档,需要通过该项目两个 Core(核心开发者)的+2评分,才会被合并到GitHub 代码仓库中,代表此次提交成功。反之,如果有人给出-1、-2的评分或 Jenkins 测试提示失败等,那么你需要针对具体的问题修改提交的内容,然后再次提交,如下图所示。
查看 OpenStack 社区贡献数据,可以访问 http://stackalytics.com,输入相应的个人名称、公司名称和 OpenStack 项目名称等进行搜索,如下图所示。
要想参与 OpenStack 社区沟通交流,一般最常用的方式是使用 E-mail 和 IRC(Internet Relay Chat,互联网中继聊天,理解为国内的 QQ 即可)。需要注意的是,由于中国时区和北美、欧洲时区存在10个小时以上的差异,使用 IRC 实时聊天工具可能存在沟通障碍问题。下面阐述如何通过这两种方式进行沟通交流。
由于 OpenStack 项目众多,为了防止邮件泛滥,通常在发送邮件时会在标题上加上项目名称作为前缀来进行区别。比如“[nova]”,表示这个邮件内容是与 Nova 相关的,如此一来,开发者便可以更有针对性地阅读邮件。
所有的邮件列表都可以在这里找到:https://wiki.openstack.org/wiki/Mailing_Lists。
至于如何订阅邮件,可以在 OpenStack Mailing List 页面中单击 Subscribe 链接,或者直接单击 OpenStack Dev Subscribe,如下图所示。
在 OpenStack Dev Subscribe 页面中输入接收邮件的邮箱地址和名字(可选),即可订阅成功。
比如,要想在 openstack-dev 邮件中提问题,只需要编辑邮件发送到 openstack-dev@ lists.openstack.org 邮箱即可,接下来需要做的就是等待别人回答你的问题,并给予积极的回应。
IRC(Internet Relay Chat)是一种实时聊天工具。由于使用邮件无法做到与社区实时互动,所以邮件更适合抛出一个问题或想法,系统性地阐述观点,并不需要立即得到他人的帮助、建议和回复等场景。
对于社区在线即时交互,OpenStack 社区推荐使用 IRC,所有的 OpenStack IRC 聊天室都可以在这里找到:https://wiki.openstack.org/wiki/IRC。比如 #openstack-dev
频道用于讨论开发过程中遇到的问题,#openstack-keystone
则用于讨论有关 Keystone 的问题。
IRC频道和项目例会固然很好,但它们也有局限性,需要考虑到他人因各种原因而未在线的问题,还有时区问题,所以邮件可以起到一个很好的弥补作用。IRC 工具种类繁多,既有 PC 端也有移动端的工具。下面是一些常用且开源的 IRC 工具。
PC 客户端工具:
移动客户端工具:
OpenStack 各项目例会的安排都列在 https://wiki.openstack.org/wiki/Meetings 上。对于OpenStack 开发者来说,参加项目例会是很重要的。项目例会一般由该项目的 PTL(项目主管)主持,鼓励该项目的所有开发者参加并讨论会议议题。项目例会是 OpenStack 开发者融入社区相当好的一个机会。
OpenStack 的 IRC 会议都有 Log 记录,可以通过 IRC 来了解项目的进展。如果你没有实时参与其中的讨论,那么可以有空时去查阅相关的记录。
OpenStack 社区使用的 IRC 服务器地址是 irc.freenode.net,端口是6665和6666。
这里,推荐使用桌面版的一款开源免费的 IRC 客户端工具,即 HexChat,它同时支持Windows、Linux 和 OS X 系统。下载地址:http://hexchat.github.io/downloads.html。安装配置后,如下图所示。
除了以上提到的,使用 E-mail 和 IRC 方式和 OpenStack 社区交流之外,还可以参加诸如 Meetup 等会议。
在介绍 OpenStack 社区 CI/CD 平台之前,有必要先直观认识下社区日常运营的工作量,这将有助于我们理解为什么社区要建设如此丰富、复杂的基础设施服务。
社区 CI 规模
社区 CI 挑战
针对所面临的规模和挑战,OpenStack 社区构筑了一套完善的 CI/CD 平台,被统称为OpenStack Infra(OpenStack 基础设施平台)。OpenStack 基础设施平台主要包括:
其中 Zuul、Jenkins-job-builder、Gearman Plugin、DevStack、Nodepool 等都是由 OpenStack 基础设施服务团队开发维护的。社区 CI/CD 系统运行工作流程如下图所示。
这里简要梳理下当社区开发人员向代码评审系统提交代码之后,代码会经过哪些环节,系统会执行哪些任务,才会最终被合并到 GitHub 代码仓库系统中。整体流程如下图所示。
首先是 PEP 8 代码风格测试。因为社区开发者人数众多,所以保证代码风格统一是非常重要的,需要确保大家都使用同样的编码方式和风格等。
然后是单元测试。仅仅测试被变更的子项目,不考虑跟其他子模块交互的情况。社区会针对不同的平台和软件版本进行测试,包括 Python 2.x 和 3.x,在不同操作系统上运行不同的软件版本。
最后是集成测试。社区在由 HP、Rackspace 等提供的 IaaS 云虚拟机上,使用 DevStack安装所有的组件,然后在这个单节点(all-in-one 环境)上运行不同的模板。不同的模板对不同的模块进行不同的配置,比如使用不同的数据库、不同的消息队列、不同的存储类型,不过基本上只测试那些常用的如 MySQL、PostgreSQL、RabbitMQ 等,当然社区也在考虑引入 ZeroMQ 的测试。
集成测试所使用的 VM 一般配置为8GB内存,系统是 Ubuntu ,然后让 DevStack 在该VM 上安装 OpenStack。Nodepool 用来管理 VM,通过缓存来预备这些机器。同时将 DevStack 所需要的依赖软件包等都预先下载到本地,这样测试本身就可以离线运行了。
测试执行完之后,再销毁这些 VM。实际创建的 VM 数量要比运行成功的测试数量多,因为 Zuul 的随机机制,有时候当测试跑到一半时才发现还需要一些其他东西,于是测试执行不下去了,此时会删除该 VM,启动一个新的。大致的比例是,如果一天跑10000个任务,那么启动的 VM 数量差不多在100000量级,即1:10的比例。
无疑,社区在测试方面做出了严格的限制,即只有写好了单元测试的代码变更提交才能够被接受。对于社区而言,未经测试的变更就是有问题的和有风险的。因为现在 OpenStack 项目发展很快,不断催生出新的组件,一个小错误就可能会影响整个系统的运行。
为了解决这些问题,社区使用了 Test Repository 框架,让大多数单元测试在这个框架中可以并行处理,并快速反馈测试结果。社区 QA 团队自行开发的 Zuul 系统,一方面可以并行测试一系列提交的代码,同时又保持它们的测试顺序不变。
OpenStack Infra资料请参考这里。
OpenStack 社区使用开源的 Jenkins 系统来负责持续集成。在应用中,Jenkins 使用 Zuul和 Gearman 进行管理。其具体的任务配置管理,使用 Jenkins-job-builder 基于 YAML 文件格式来定义 Job 内容,采用命令行创建和管理 Jenkins Job,Job 文件采用 Git 版本控制工具进行管理。OpenStack 的使用方式为:
Pipeline 的字面意思就是流水线,是很好用的一个 Jenkins 插件,将很多步骤按顺序排列好,结束一个后执行下一个。在真实的工作环境中有很多 Job,比如先编译,然后执行代码静态检查、单元测试,最后部署服务、重启服务、进行 UI 测试等。我们需要对这些 Job 进行一些设置,将它们的上下游关系配置好。Pipeline 提供了图形界面,可以在界面上形象地看到整个构建任务的执行流程和完成度。示例如下。
Job模板:
- job-template: name: 'gate-{name}-docs' builders: - shell: 'git checkout {branch_name}'
Jenkins-job-builder项目定义:
- project: name: project-name branch_name: new_branch jobs: - gate-{name}-docs
Job分组管理:
- job-group: name: '{name}-tests' jobs: - '{name}-unit-tests' - '{name}-perf-tests'
Job定义:
- job: name: foo-test project-type: freestyle builders: - make-test publishers: - archive
可以在 Job 文件中增加模块,比如 Builder、Publisher 等,使用宏(即批量处理,就是将一些命令组织在一起,作为一个单独命令完成某个特定任务)来定义 Jenkins 需要执行的任务。
- builder: name: make-test builders: - shell: 'make test'
Jenkins-job-builder(简称 JJB)是用来创建 Jenkins 任务的工具。为了简化配置大量 Jenkins任务的工作量,OpenStack 采用更容易阅读的基于 YAML 或 JSON 格式的文件来编辑任务,然后使用 JJB 将 YAML 或 JSON 格式的配置转化为可以被 Jenkins 理解的 XML 格式的任务配置文件,并更新到 Jenkins 中。
实际上,Jenkins创建的任务是以 XML 文件的格式保存在 $JENKINS_HOME/jobs/ [job-name]/config.xml
中的,JJB 能够将 YAML 转化为 XML 文件(借助 Jenkins 提供的命令接口),并更新到 Jenkins 中。
这里,以测试配置、更新任务以及删除任务为例,阐述Jenkins-job-builder方法的使用。
(1)首先,安装Jenkins-job-builder。
# pip install jenkins-job-builder
(2)测试配置任务。
当任务配置的 YAML 文件编写完成之后,可以通过“jenkins-jobs test”测试配置格式和内容是否正确。
# jenkins-jobs test path/to/myjob.yaml
若测试通过,将输出 XML 格式的任务配置;如果想将测试的 XML 格式的任务配置输出到文件,则可以添加“-o”参数。
# jenkins-jobs test -o output path/to/myjob.yaml
JJB 将在与 myjob.yaml 相同的目录下新建一个名为“output”的文件夹,并在其内创建一个用 YAML 中定义的任务名命名的文件,就是 XML 格式的任务配置文件。
(3)更新任务。
测试通过后,可以使用“jenkins-jobs update”命令将 YAML 文件定义的任务更新到 Jenkins中。
# jenkins-jobs [--conf jenkins_jobs.ini] update path/to/job1.yaml
Update 命令需要指定保存有 Jenkins 服务器信息的配置文件,用“--conf”来显式指定该配置文件,如果不显式指定,则默认读取“/etc/jenkinsjobs/jenkinsjobs.ini”文件。该配置文件保存有 Jenkins 的 URL 和登录信息,内容如下:
[jenkins] user=jenkins password=password url=http://localhost:8081/jenkins
从而 JJB 可以将任务更新到 ini 配置文件指定的Jenkins系统中。路径也可以是目录,那么就是更新指定目录下所有的YAML、YML和JSON文件,多个路径用冒号隔开。
(4)删除任务。
删除任务使用如下命令:
# jenkins-jobs [--conf jenkins_jobs.ini] delete job1
其中 job1 为任务名称。
在 OpenStack 环境中,可以在 project-config:jenkins/jobs/ 目录下找到 YAML 脚本文件。在该目录下有4种配置文件。
(1)defaults.yaml 文件
该文件为全局默认配置文件,是所有 Jenkins 任务的全局属性定义,即 name 为“global”的属性,比如默认的描述、任务是并行执行的、任务超时时间为30分钟等。
(2)macros.yaml文件
该文件保存了所有的宏定义,包括一些比较通用的 builders 或 publishers,供各任务调用,如下所示。
- builder: name: git-prep builders: - shell: "/slave_scripts/git-prep.sh" - publisher: name: console-log publishers: - scp: site: 'scp-server' files: - target: 'logs/$JOB_NAME/$BUILD_NUMBER' copy-console: true copy-after-failure: true
(3)
该文件为各个项目的配置脚本,任务和任务模板定义在各个项目的脚本文件中。每个项目都有一个以项目名命名的
文件,里面的内容基本就是“- job:”和“- job-template:”,还有“- job-groups:”。
(4)projects.yaml 文件
该文件包含了所有项目的 Job 配置,即所有项目均集中配置在 projects.yaml 文件中,各个项目以字母顺序排列,各项目的 job 属性来自于任务和任务模板的定义。
针对 Jenkins-job-builder 的单独介绍,请访问这里。
Jenkins-job-builde 配置实例,请查看这里。
Gearman 是一个分布式队列系统,负责将合适的任务分发到多台机器上,以便快速分解完成大型任务。Gearman 架构示意图如下图所示。
Gearman通常由三部分组成,即 Client、Worker 和 Job Server(任务服务器)。由 Worker执行 Client 发来的 Job,再通过 Job Server 返回给 Client。Gearman 提供了 Client、Worker 的 API,利用这些 API 与 Job Server 通信。
Gearman 接收到来自 Jenkins 的分发任务后,将 Job 发送到具体的工作节点上。Gearman和 Jenkins 系统集成示意图如下图所示。流程如下:
简单而言,Zuul 是一个面向多项目配置与自动化检测代码测试是否通过的系统。它同时与Gerrit、Jenkins 进行消息通信,使用 layout.yaml 文件进行灵活配置,适合多种项目的自动化操作,可以并行执行一系列变更的测试。
Zuul 有两个主要组件分别为 scheduler 和 merger。Zuul 保证合并进入源代码库的代码变更都是通过测试的。比如通过监测 Gerrit 的事件以触发相应的 Pipeline 及其对应的 Job,从代码的提交,到社区人员评审的 -1/+1、-2/+2 等事件流触发相应操作。
如下是社区的 OpenStack Nova 计算项目的一个 Zuul 配置文件。
projects: - name: OpenStack/nova check: - gate-nova-pep8 - gate-nova-docs - gate-nova-Python27 - gate-Tempest-devstack-vm-full gate: - gate-nova-pep8 - gate-nova-docs - gate-nova-Python27 - gate-Tempest-devstack-vm-full experimental: - gate-devstack-vm-cells slient: - gate-Tempest-devstack-vm-large-ops post: - nova-branch-tarball - nova-coverage - nova-docs - nova-upstream-translation-update pre-release: - nova-tarball release: - nova-tarball - nova-docs periodic: - nova-propose-translation-update - periodic-nova-Python27-stable-folsom - periodic-nova-Python27-stable-grizzly
这里有一个特性是预测执行,即预测并提前执行可能需要的任务,以便加速整个处理过程。这个特性在 Pipeline 中得到了广泛使用,以提高整体效率。比如 Nodepool 会预先在 OpenStack 云环境中创建好相应的虚拟机;DevStack 会事先将相应的依赖包和其他项目源码下载下来,以便快速安装单节点的 OpenStack 测试环境。
一个 Check Pipeline 文件内容如下:
pipelines: - name: check manager: IndependentPiplelineManager precedence: low trigger: Gerrit: - event: patchset-created success: Gerrit: verified: 1 failure: Gerrit: verified: -1
一个 Gate Pipeline 文件内容如下:
pipelines: - name: name manager: DependentPiplelineManager precedence: high trigger: Gerrit: - event: comment-added approval: - approved: 1 start: Gerrit: verified: 0 success: Gerrit: verified: 2 submit: true failure: Gerrit: verified: -2
一个 Zuul 任务队列的文件内容如下:
projects: - name: OpenStack/nova gate: - gate-nova-Python27 - gate-Tempest-devstack-vm - name: OpenStack/glance gate: - gate-glance-Python27 - gate-Tempest-devstack-vm
在回答该问题之前,我们需要先认识下 OpenStack 代码的提交与合并过程。
首先,开发人员克隆相关的 OpenStack 项目(如 Keystone、Nova 等),做了代码(也包括 rst 文档)修改后,使用 git 命令提交到代码评审系统中。
然后,Jenkins 做自动化测试。Jenkins 可能会运行一个或多个工作任务来执行不同类型的测试,以验证这些提交的 Patch(补丁)是否安全、正确。这些工作便被称为“Gate Job”。
这里 Gate 可以被形象地理解为“看门人”。社区开发人员提交的 Patch 是否得到批准,是根据 Jenkins Gate Job 执行的测试结果来确定的。然后基于测试结果,将 -1/+1 的投票反馈到代码评审系统(Gerrit)中。
在这里,我们可以找到 OpenStack 每个项目的 Gate Job 配置文件,这些配置文件均采用YAML 文件格式编写。这里是链接地址。
如果想知道向社区提交代码后,Jenkins 会执行哪些任务,一个直接的办法是在 Gerrit 系统中查看。还有一个办法则是查看项目的配置文件:project-config/zuul/layout.yaml。通过该链接地址,可以找到 OpenStack 项目的模板文件内容。
首先需要选择哪些项目属于这个 Job。在 projects.yaml 文件中可以看到所有项目的 Job。点击这里获得链接地址:。
比如将一个名称为“abregman-new-job”的 Job 添加到“devstack-jobs”项目下。
jobs:
- gate-Tempest-dsvm-{name}{job-suffix}: pipeline: gate name: abregman-new-job node: devstack-centos7 job-suffix: ''
文件中的“node:devstack-centos7”用于告诉 Jenkins 在哪些节点上运行任务。devstack-centos7只是一个节点的标签。所以,当 Job 运行时,它将寻找标签为“devstack-centos7”的节点。
假设每次提交 Patch 时,都要运行“openstack-dev/devstack”这个 Job,则可以这样编写:
- name: openstack-dev/devstack gate: - gate-Tempest-abregman-new-job
现在,我们添加了一个 Job(gate-Tempest-abregman-new-job)到“openstack-dev/devstack”项目中,并在 Gate Pipeline Job 下。这样,当上述代码内容提交并合并后,就可以提交 Patch 到 openstack-dev/devstack 项目中,来观察它们的 Job 是如何运行的。一个全局的社区 Zuul Job 运行状态如下图所示。
社区采用了开源的 Gerrit 系统用于代码评审,以及细粒度的开发者权限控制等。而第三方系统与 Gerrit 的集成主要通过 Webhooks、event-stream、REST API 等方式交互。
通常,Gerrit评审系统上的代码有如下几种状态。
相应地,Gerrit 的触发类型有如下几种。
通常将 Gerrit 评论页面中显示的 Jenkins Job 执行结果和耗时时间,作为代码评审的依据。还有一个 Gerrit 的辅助配置工具 Jeepyb,它是一个帮助简化 Gerrit 管理的工具集,可以很简便地管理项目并和 Launchpad、GitHub 等系统进行集成。在 Jeepyb 中采用 YAML 文件定义项目。
- project: example/Gerrit description: Fork of Gerrit used by Example- project: OpenStack/project-name acl-config: /home/gerrit2/acls/project-name.config upstream: git://github.com/awesumsauce/project-name.git
Jeepyb 基于 Gerrit 进行分组,将 Administrators、Registered Users、Anonymous Users 用户组划分在每个项目中,针对每个项目都有一个 ACL(访问控制列表)的配置文件。Jeepyb 描述项目和分值的权限采用 git refs 的语法格式。
[access "refs/heads/*"]label-Code-Review = -2..+2 group project-name-corelabel-Workflow = -1..+1 group project-name-core[access "refs/heads/proposed/*"]label-Code-Review = -2..+2 group project-name-milestonelabel-Workflow = -1..+1 group project-name-milestone[receive]requireChangeId = truerequireContributorAgreement = tree[submit]mergeContent = true
在 Gerrit 系统中,修改 etc/gerrit.config 配置文件,如下所示。
[commentlink "launchpad"] match = "([Bb]ug\\s+#?)(\\d+)" link = https://bugs.launchpad.net/mahara/+bug/$2
OpenStack 社区遵循的原则是人人平等,即每个人提交的代码都需要经过相同的验证测试和其他人员的评审,只有通过了,其代码才能被合并到仓库中。在代码评审系统中评分有0、-1/+1、-2/+2这几项,具体含义如下表所示。
分值 | 含义 |
---|---|
0 | 不计分,即该项分值不会被统计到stackalytics.com中 |
-1 | 对于评审人员而言,这个提交是需要修改的 |
+1 | 对于评审人员而言,这个提交是不错的,但是还需要其他人批准 |
-2 | 严重错误,不能合并到项目中 |
+2 | 对于核心评审者而言,这个提交很好,同意合并代码 |
通常给出评分为-1、-2的评审人员,需要进行评论,阐明其为什么是错误的,或者说明应该怎样修改。这些评论可以帮助提交者或其他评审人员重新更新和评审。核心评审者能够给予分值为 -2/+2 的投票并批准提交,一旦有两个核心评审者给了+2分值,那么代码就会被合并到 GitHub 项目中。
Software Factory 是一个由 Red Hat 开源的用于在 OpenStack 云平台和其他环境中部署的CI/CD 项目,该项目集成了 Jenkins、Zuul、Gerrit、Nodepool、Redmine 等系统,支持从源代码提交,到编译打包和部署,再到项目管理等任务。
Software Factory可以安装在 OpenStack 云平台上,也可以安装在 LXC 容器中及虚拟机上等。如果需要使用 Nodepool 在 Jenkins Slave 节点上管理 Job、测试等任务,或者将应用 push 到 Swift 对象存储上,那么需要:
Red Hat 官方提供了不同版本的 Software Factory 的 qcow2 镜像,用于作为虚拟机来直接使用。如何在 OpenStack 云平台上部署 Software Factory 项目呢?这里使用命令行方式部署,执行如下步骤。
(1)下载镜像。
# wget http://46.231.133.241:8080/v1/AUTH_sf/sf-images/softwarefactory-C7. 0-2.2.2.img.qcow2
(2)生成镜像。
# glance image-create --progress --disk-format qcow2 --container-format bare --name sf-2.2.2 --file softwarefactory-C7.0-2.2.2.img.qcow2
(3)使用镜像创建虚拟机。
# nova boot --image sf-2.2.2 --flavor 4 --nic net-id=b6c3b5d7-73b3-4b6d-8b3b-2a543ce91bee software_factory
(4)在 Dashboard 界面上,绑定一个外网 IP 地址给虚拟机。
(5)在浏览器中,使用该外网 IP 地址访问 Software Factory 系统,并可以使用 GitHub 账号登录 Software Factory,如下图所示。
可以在系统的导航栏中看见该平台集成了很多子系统,用于负责不同的任务。Software Factory 非常适用于中小型规模的研发测试环境,通过高度集成、简化的自动化部署方式等,在使用方面显得非常简便。无论是 Gerrit、Jenkins 还是 Redmine等,均可以在其上面自行创建项目、分配权限、管理日常开发等。
阅读全文: http://gitbook.cn/gitchat/column/5aa795539c3cf94d49162f03