(图片由Computerizer在Pixabay上发布)
你好
我的名字叫
Evgeny Cherkin ,我是
Polymetal矿业公司开发团队的程序员。
在开始任何重大项目时,您都会开始思考:“哪种软件最好用于维护?”。 下一个版本发布之前的IT项目经历了一系列阶段。 这些步骤的链是自动化的,那很好。 发布IT项目新版本的自动化过程称为“
持续集成” 。
事实证明,
BuildBot对我们来说是一个很好的帮助,它可以执行此过程。
在本文中,我决定概述
BuildBot的功能。 这个软件能做什么? 如何接近他,如何与他建立正常的有效工作关系? 您还可以通过在计算机上创建一个用于组装和测试项目的工作服务,将我们的经验运用到自己身上。
1.为什么是BuildBot?
早在habr-e时,我遇到了有关使用
BuildBot实现
持续集成的 文章 。 例如,在我看来,
这是最有用的。 还有另一个例子-
更简单 。 这些文章可以使用
手册中的示例进行调味,之后是英语。 轿跑车是一个很好的起点。 阅读完这些文章之后,您可能会立即想要在
BuildBot上做一些事情。
别说了 有人在项目中使用过吗? 事实是,
许多人已将其应用于任务中。 您可以在Google代码档案中找到使用
BuildBot的 示例 。
那么人们使用
buildbot的逻辑是什么? 毕竟,还有其他工具:
CruiseControl和
Jenkins 。 我会这样回答。 对于大多数任务,
詹金斯确实足够了。
BuildBot则更具适应性,并且在那里的任务像在
Jenkins中一样容易解决。 选择你 但是,由于我们正在寻找用于开发目标项目的工具,所以为什么不选择一个允许我们从简单的步骤开始,获得具有交互性和独特界面的构建系统的工具。
对于那些目标项目是用python编写的人来说,就会出现一个问题:“为什么不选择一个在项目所用语言方面具有清晰界面的集成系统?”。 然后是时候介绍
BuildBot的好处了。
因此,我们的“乐器四重奏”。 我自己定义了BuildBot的四个功能:
- 这是GPL下的开源框架
- 这是使用python作为配置工具并描述了所需的操作。
- 这是从发生装配的机器接收响应的机会。
- 这些最终是主机的最低要求。 部署需要使用python和twisted,并且不需要虚拟机或java机器。
2. BuildMaster领导的概念

任务分发架构的中心是
BuildMaster 。 它是一项服务:
- 跟踪项目源代码树中的更改
- 发送工人服务应执行以构建项目并对其进行测试的命令
- 通知用户所采取措施的结果
BuildMaster是通过
master.cfg文件配置的。 该文件位于
BuildMaster的根目录。 稍后,我将说明如何创建此根。
master.cfg文件
本身包含python,这是一个使用
BuildBot调用的脚本。
下一个最重要的
BuildBot称为
Worker 。 此服务可以在具有不同操作系统的其他主机上运行,也可以在
BuildMaster所在的位置上
运行 。 它也可以存在于具有其自己的程序包和变量的经过特殊准备的虚拟环境中。 可以使用
vertualenv,venv等python实用工具准备这些虚拟环境。
BuildMaster将命令广播给每个
Worker ,然后由他们执行它们。 也就是说,事实证明,构建和测试项目的过程可以转到Windows下的
Worker以及Linux下的另一个Worker。
项目源代码
的检出发生在每个
Worker上 。
3.安装
所以走吧 我将使用Ubuntu 18.04作为主机。 在其上,我将放置一个
BuildMaster -a和一个
Worker -a。 但首先您需要安装python3.7:
sudo apt-get update sudo apt-get install python3.7
对于需要python3.7.2而不是3.7.1的用户,可以执行以下操作:
sudo apt-get update sudo apt-get software-properties-common sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get install python3.7 sudo ln -fs /usr/bin/python3.7 /usr/bin/python3 pip3 install --upgrade pip
下一步是安装
Twited和
BuildBot以及启用其他
BuildBot -a功能的软件包。
/* sudo /usr/local/lib/python3.7/dist-packages*/
4.第一步
是时候创建一个
BuildMaster了 。 我们将把它放在文件夹
/ home / habr / master中 。
mkdir master buildbot create-master master
下一步。 创建一个
工人 。 我们将把它放在文件夹
/ home / habr / worker中 。
mkdir worker buildbot-worker create-worker --umask=0o22 --keepalive=60 worker localhost:4000 yourWorkerName password
启动
Worker时 ,默认情况下,它将在
/ home / habr / worker中创建一个文件夹,其中包含项目的名称,该名称在
master.cfg中指定。 然后在带有项目名称的文件夹中,他将创建
构建目录,然后在其中进行
签出 。
Worker的工作目录将是目录
/ home / habr / yourProject / build 。
金钥匙现在,对于我之前写的内容:由于该脚本没有运行权限,因此将不会执行
Master将要求
Worker在该目录中远程执行的脚本。 要解决这种情况,您需要一把钥匙
--umask = 0o22 ,这禁止写入该目录,但
保留启动权限。 我们只需要这个。
BuildMaster和
Worker之间建立了联系。 碰巧它中断了,
Worker等待
BuildMaster的响应一段时间。 如果未收到响应,则重新启动连接。 密钥
--keepalive = 60正是您需要指示
连接重新启动之后的时间。
5.配置。 逐步食谱
BuildMaster配置在机器端完成,我们在其中运行了
create-master命令。 在我们的例子中,这是目录
/ home / habr / master 。
master.cfg配置文件尚不存在,但是命令本身已经创建了
master.cmg.sample文件。 您需要将其在
master.cfg.sample中重命名为
master.cfg mv master.cfg.sample master.cfg
让我们打开这个
master.cfg 。 我们将分析它的组成。 之后,我们将尝试制作自己的配置文件。
master.cfg c['change_source'] = [] c['change_source'].append(changes.GitPoller( 'git://github.com/buildbot/hello-world.git', workdir='gitpoller-workdir', branch='master', pollInterval=300)) c['schedulers'] = [] c['schedulers'].append(schedulers.SingleBranchScheduler( name="all", change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=["runtests"])) c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=["runtests"])) factory = util.BuildFactory() factory.addStep(steps.Git(repourl='git://github.com/buildbot/hello-world.git', mode='incremental')) factory.addStep(steps.ShellCommand(command=["trial", "hello"], env={"PYTHONPATH": "."})) c['builders'] = [] c['builders'].append( util.BuilderConfig(name="runtests", workernames=["example-worker"], factory=factory)) c['services'] = [] c['title'] = "Hello World CI" c['titleURL'] = "https://buildbot.imtqy.com/hello-world/" c['buildbotURL'] = "http://localhost:8010/" c['www'] = dict(port=8010, plugins=dict(waterfall_view={}, console_view={}, grid_view={})) c['db'] = { 'db_url' : "sqlite:///state.sqlite", }
5.1 BuildmasterConfig
c = BuildmasterConfig = {}
BuildmasterConfig-配置文件的基本字典。 它必须包含在配置文件中。 为了易于使用,在配置代码中输入了别名
“ c” 。
c [“ keyFromDist”]中的
键名是用于与
BuildMaster进行交互的固定元素。 在每个键下,将相应的对象替换为一个值。
5.2工人
c['workers'] = [worker.Worker("example-worker", "pass")]
这次我们指出了
BuildMaster 工人列表。 我们通过指定
you-worker-name和
password在
上面创建了
Worker 。 现在必须指定它们,而不是
example-worker和
pass 。
5.3 change_source
c['change_source'] = [] c['change_source'].append(changes.GitPoller( 'git://github.com/buildbot/hello-world.git', workdir='gitpoller-workdir', branch='master', pollInterval=300))
使用c词典
的change_source键,我们可以访问列表,该列表将您要放置的项目的源代码轮询存储库。 该示例使用Git存储库,该存储库会定期轮询。
第一个参数是存储库的路径。
workdir是指向
Worker一侧的文件夹的路径,相对于
/ home / habr / worker / yourProject / build路径
, git将存储版本库的本地版本。
分支包含存储库中应监视的特定分支。
pollInterval包含
BuildMaster将轮询存储库以查找更改的秒数。
有几种方法可以跟踪项目存储库中的更改。
最简单的方法是
Polling ,这意味着
BuildMaster会定期使用存储库轮询服务器。 如果
提交反映了存储库中的更改,则
BuildMaster会
稍有延迟地创建一个内部
Change对象,并将其发送到
Scheduler事件处理程序,该事件处理程序将开始在
Worker上构建和测试项目的步骤。 在这些步骤中,将指示存储库的
更新 。 在
Worker上将创建存储库的本地副本。 该过程的详细信息将在下面的两个部分
( 5.4和5.5 )中公开。
跟踪存储库中的更改的一种更为优雅的方法是直接从其所在的服务器向
BuildMaster发送有关更改项目源代码的消息。 在这种情况下,一旦开发人员进行了
提交 ,具有项目存储库的服务器就会向
BuildMaster发送一条消息。 然后,将通过创建
PBChangeSource对象来拦截该对象。 此外,该对象将被传送到
Scheduler ,后者将激活项目的组装和测试步骤。 该方法的重要部分是使用存储库中的服务器
挂钩脚本。 在负责处理
提交期间操作的
挂钩脚本中,您需要调用
sendchange实用程序并指定
BuildMaster的网络地址。 您必须
指定将侦听
PBChangeSource的网络端口。
顺便说一句 ,
PBChangeSource是BuildMaster的一部分。 此方法在项目存储库所在的服务器上需要
admin -a特权。 首先,您需要制作一个备份存储库。
5.4排放者
c['schedulers'] = [] c['schedulers'].append(schedulers.SingleBranchScheduler( name="all", change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=["runtests"])) c['schedulers'].append(schedulers.ForceScheduler( name="force", builderNames=["runtests"]))
调度程序是一个元素,可作为触发器运行项目的整个组装和测试链。

由
change_source记录的那些更改在
BuildBot -a操作期间被转换为
Change对象,现在每个基于它们的
Sheduler都生成了启动项目构建过程的请求。 但是,它也确定何时将这些请求发送到队列。 对象
Builder保留请求队列,并在单独的
Worker -e上监视当前程序集的状态。
BuildMaster -e和
Worker -e上
都存在
Builder 。 他将特定的
构建从
BuildMaster发送到
Worker ,必须遵循一系列步骤。
我们看到,在此类
调度程序的当前示例中,创建了2件。 而且,每个都有自己的类型。
SingleBranchScheduler是最受欢迎的日程表类之一。 它监视一个分支,并由其中的记录更改触发。 当他看到更改时,可以推迟发送构造请求(推迟特殊参数
treeStableTimer中指定的时间段)。 该
名称指定将在
BuildBot -web界面中显示的调度的名称。 在
ChangeFilter中设置一个
过滤器后,分支中的更改将通过该
过滤器提示时间表以发送构建请求。 在
builderNames中指定了名称
builder -a,稍后再指定。 在我们的案例中,该名称将与项目的名称相同:
yourProject 。
ForceScheduler是一件非常简单的事情。 这种类型的计划是通过在
BuildBot -web界面上单击鼠标触发的。 参数与
SingleBranchScheduler具有相同的本质。
PS 3号 突然派上用场定期是按特定的固定频率触发的计划。 看起来像这样的电话
from buildbot.plugins import schedulers nightly = schedulers.Periodic(name="daily", builderNames=["full-solaris"], periodicBuildTimer=24*60*60) c['schedulers'] = [nightly]
5.5建造工厂
factory = util.BuildFactory() factory.addStep(steps.Git(repourl='git://github.com/buildbot/hello-world.git', mode='incremental')) factory.addStep(steps.ShellCommand(command=["trial", "hello"], env={"PYTHONPATH": "."}))
PeriodicalBuildTimer以秒为单位设置此周期性的时间。
BuildFactory创建一个具体的
构建 ,然后
构建器将其发送给
Worker 。
BuildFactory指示
Worker应该遵循的步骤。 通过调用
addStep方法添加步骤
。
在此示例中添加的第一步是
git clean -d -f -f –x ,然后是
git checkout 。 这些动作嵌入在
方法参数中,该参数未明确指出,但暗含了默认值
fresh 。
mode ='incremental'参数指示完成存储的目录中的文件(尽管从存储库中丢失)保持不变。
添加的第二个步骤是使用环境变量PATHONPATH = ...从目录
/ home / habr / worker / yourProject / build中使用带有变量
hello的hello参数调用
试验脚本,因此您可以编写自己的脚本并在
Worker端执行-a通过
util.ShellCommand步骤。 这些脚本可以直接放入存储库中。 然后在
开票期间,他们将转到
/ home / habr / worker / yourProject / build 。 但是,这里有两个“ buts”:
- 必须使用--umask开关创建Worker ,以便在签出 -a之后不会阻止执行权限。
- 当git push这些脚本时,必须指定exacutable属性,以便使用chechout -e Git不会失去执行脚本的权利。
5.6建筑商
c['builders'] = [] c['builders'].append(util.BuilderConfig(name="runtests", workernames=["example-worker"], factory=factory))
关于
此处描述
了什么
Builder 。 现在,我将详细讨论如何创建它。
BuilderConfig是构造函数
builder 。 您可以在
c ['builders']中指定多个此类构造函数,因为这是一系列构造
器类型对象的列表。 现在,我们将稍微重写
BuildBot中的示例,使其更接近我们的任务。
c['builders'] = [] c['builders'].append(util.BuilderConfig(name="yourProject", workernames=["yourWorkerName"], factory=factory))
现在,我将介绍参数
BuilderConfig 。
name设置名称
构建器 -a。 在这里,我们将其称为
yourProject 。 这意味着将在
Worker上创建此路径
/ home / habr / worker / yourProject / build 。
Sheduler用该名称搜索
构建器 。
workernames包含一个
Workers列表。 每个都必须添加到
c ['workers']中 。
factory是与
构建器关联的特定
构建 。 它将向
构建器发送一个
构建对象,以完成构成该
构建 -a的所有步骤。
6.自己的配置示例
这是我建议通过
BuildBot实现的示例项目架构
。
我们将使用
svn作为版本控制系统。 存储库本身将位于特定的云中。 这是此云的地址
svn.host/svn/yourProject/trunk 。 在
svn下的云中,有一个用户名:
user ,passwd:
密码帐户。 作为
build -a步骤的脚本也将位于
svn分支的单独
buildbot / worker_linux文件夹中 。 这些脚本位于存储库中,并保存了
可执行文件属性。
BuildMaster和
Worker在同一
project.host主机上工作。
BuildMaster将其文件存储在
/ home / habr / master文件夹中。
Worker存储以下路径
/ home / habr / worker 。
BuildMaster和
Worker进程之间的通信是使用
BuildBot -a协议(即
“ pb”协议)通过4000端口进行的。
目标项目完全用python编写。 任务是跟踪其更改,创建可执行文件,生成文档,进行测试。 万一发生故障,所有开发人员都需要向邮件发送一条消息,说明操作失败。
我们将把
BuildBot Web映射连接到
project.host的端口80。 修补程序是可选的。
扭曲的库已经有一个Web服务器,
BuildBot使用它。
我们将使用
sqlite存储
BuildBot的内部信息。
对于邮件发送,您需要主机
smtp.your.domain-它允许从
projectHost@your.domain发送电子邮件而无需身份验证。 同样在主机“
smtp ”上,该协议在1025年被侦听。
此过程涉及两个人:
admin和
user 。 admin管理
BuildBot 。 用户是提交提交的
人 。
可执行文件是通过
pyinstaller生成的。 文档是通过
doxygen生成的。
对于这种架构,我编写了这个
master.cfg :
master.cfg import os, re from buildbot.plugins import steps, util, schedulers, worker, changes, reporters c= BuildmasterConfig ={} c['workers'] = [ worker.Worker('yourWorkerName', 'password') ] c['protocols'] = {'pb': {'port': 4000}} svn_poller = changes.SVNPoller(repourl="https://svn.host/svn/yourProject/trunk", svnuser="user", svnpasswd="password", pollinterval=60, split_file=util.svn.split_file_alwaystrunk ) c['change_source'] = svn_poller hourlyscheduler = schedulers.SingleBranchScheduler( name="your-project-schedulers", change_filter=util.ChangeFilter(branch=None), builderNames=["yourProject"], properties = {'owner': 'admin'} ) c['schedulers'] = [hourlyscheduler] checkout = steps.SVN(repourl='https://svn.host/svn/yourProject/trunk', mode='full', method='fresh', username="user", password="password", haltOnFailure=True) projectHost_build = util.BuildFactory() cleanProject = steps.ShellCommand(name="Clean", command=["buildbot/worker_linux/pyinstaller_project", "clean"] ) buildProject = steps.ShellCommand(name="Build", command=["buildbot/worker_linux/pyinstaller_project", "build"] ) doxyProject = steps.ShellCommand(name="Update Docs", command=["buildbot/worker_linux/gendoc", []] ) testProject = steps.ShellCommand(name="Tests", command=["python","tests/utest.py"], env={'PYTHONPATH': '.'} ) projectHost_build.addStep(checkout) projectHost_build.addStep(cleanProject) projectHost_build.addStep(buildProject) projectHost_build.addStep(doxyProject) projectHost_build.addStep(testProject) c['builders'] = [ util.BuilderConfig(name="yourProject", workername='yourWorkerName', factory=projectHost_build) ] template_html=u'''\ <h4> : {{ summary }}</h4> <p> : {{ workername }}</p> <p>: {{ projects }}</p> <p> : {{ buildbot_url }}</p> <p> : {{ build_url }}</p> <p> WinSCP c ip:xxx.xx.xxx.xx. habr/password, executable ~/worker/yourProject/build/dist.</p> <p><b> Buildbot</b></p> ''' sendMessageToAll = reporters.MailNotifier(fromaddr="projectHost@your.domain", sendToInterestedUsers=True, lookup="your.domain", relayhost="smtp.your.domain", smtpPort=1025, mode="warnings", extraRecipients=['user@your.domain'], messageFormatter=reporters.MessageFormatter( template=template_html, template_type='html', wantProperties=True, wantSteps=True) ) c['services'] = [sendMessageToAll] c['title'] = "The process of bulding" c['titleURL'] = "http://project.host:80/" c['buildbotURL'] = "http://project.host" c['www'] = dict(port=80, plugins=dict(waterfall_view={}, console_view={}, grid_view={})) c['db'] = { 'db_url' : "sqlite:///state.sqlite" }
首先,您需要
创建 BuildMaster和
Worker -a。 然后将此
master.cfg文件粘贴到
/ home / habr / master中 。
下一步是启动
BuildMaster服务
sudo buildbot start /home/habr/master
然后启动
Worker -a服务
buildbot-worker start /home/habr/worker
做完了! 现在,
Buildbot将跟踪更改并在
svn中的 commit上
执行 ,遵循使用上述架构构建和测试项目的步骤。
下面,我将描述上述
master.cfg的一些功能
。
6.1在通往master.cfg的途中
在编写
master.cfg时,会发生很多错误,因此您需要读取日志文件。 它既存储在
BuildMaster -ec绝对路径
/home/habr/master/twistd.log上,又存储在
Worker -a侧,绝对路径为
/home/habr/worker/twistd.log 。 当您阅读并修复错误时,将需要重新启动
BuildMaster -a服务。 方法如下:
sudo buildbot stop /home/habr/master sudo buildbot upgrade-master /home/habr/master sudo buildbot start /home/habr/master
6.2使用svn
svn_poller = changes.SVNPoller(repourl="https://svn.host/svn/yourProject/trunk", svnuser="user", svnpasswd="password", pollinterval=60, split_file=util.svn.split_file_alwaystrunk ) c['change_source'] = svn_poller hourlyscheduler = schedulers.SingleBranchScheduler( name="your-project-schedulers", change_filter=util.ChangeFilter(branch=None), builderNames=["yourProject"], properties = {'owner': 'admin'} ) c['schedulers'] = [hourlyscheduler] checkout = steps.SVN(repourl='https://svn.host/svn/yourProject/trunk', mode='full', method='fresh', username="user", password="password", haltOnFailure=True)
首先,看一下
svn_poller 。 该接口与每分钟定期轮询存储库的接口相同。 在这种情况下,
svn_poller仅访问
中继分支。 神秘的参数
split_file = util.svn.split_file_alwaystrunk设置规则:如何将
svn文件夹的结构拆分为分支。 他为他们提供了相对的方式。 反过来,
split_file_alwaystrunk通过说只有
主干在存储库中来简化了过程。
在
Schedulers中 ,
指定ChangeFilter ,它看到
None,并通过
split_file_alwaystrunk根据指定的关联将
主干分支与其关联。 响应
主干中的更改,它将启动名为
yourProject的
构建器 。
需要此处的
属性 ,以便管理员作为过程的所有者从装配和测试结果中接收新闻通讯。
build -a
checkout步骤能够完全删除
Worker存储库的本地版本中的所有文件。 然后执行完整的
svn更新 。 该模式通过参数
mode = full ,
method = fresh进行配置 。
haltOnTailure参数指示,如果
svn更新 不成功 ,则应暂停整个组装和测试过程,因为进一步的步骤没有意义。
6.3给您的信:记者有权声明
记者是邮件通知服务。
template_html=u'''\ <h4> : {{ summary }}</h4> <p> : {{ workername }}</p> <p>: {{ projects }}</p> <p> : {{ buildbot_url }}</p> <p> : {{ build_url }}</p> <p> WinSCP c ip:xxx.xx.xxx.xx. habr/password, executable ~/worker/yourProject/build/dist.</p> <p><b> Buildbot</b></p> ''' sendMessageToAll = reporters.MailNotifier(fromaddr="projectHost@your.domain", sendToInterestedUsers=True, lookup="your.domain", relayhost="smtp.your.domain", smtpPort=1025, mode="warnings", extraRecipients=['user@your.domain'], messageFormatter=reporters.MessageFormatter( template=template_html, template_type='html', wantProperties=True, wantSteps=True) ) c['services'] = [sendMessageToAll]
它可以通过
多种方式发送消息。
MailNotifier使用邮件发送通知。
template_html设置新闻通讯的文本模板。 要创建标记,请使用html。 它是由
jinja2引擎修改的(可以与
django进行比较)。
BuildBot具有一组变量,在形成消息文本的过程中,将其值替换为模板。 这些变量刻在{{double花括号}}中。 因此,例如,
摘要显示已完成操作的状态,即成功或失败。
项目将输出
yourProject 。 因此,使用
jinja2 ,
BuildBot变量和python字符串格式化程序中的控制命令,您可以创建非常有用的消息。
MailNotifier包含以下参数。
fromaddr-每个人都将从其接收新闻通讯的地址。
sendToInterestedUsers = True向进行提交的所有者和用户发送一条消息。
查找 -后缀添加到接收时事通讯的用户名中。 因此,作为用户的
管理员将通过admin@your.domain接收时事通讯。
relayhost指定打开
smtp服务器的主机名,
smptPort指定
smtp服务器侦听的端口号。
mode =“ warning”表示只有在至少一个构建步骤以失败或警告状态结束的情况下,才应进行邮件发送。如果成功,则不需要邮寄。extraRecipients包含一个列表,除了所有者和提交者之外,还应向他们发送邮件。messageFormatter是一个对象,用于定义消息的格式,其模板以及jinja2中可用的变量集。诸如wantProperties = True和wantSteps = True之类的参数指定了这组可用变量。与['services'] = [sendMessageToAll]提供服务列表,其中包括我们的记者。我们做到了!恭喜你
我们创建了自己的配置,并看到了BuildBot具备的功能。我认为,这足以了解是否需要使用此工具来创建您的项目。他对你感兴趣吗?它会为您派上用场吗?方便吗?然后,我有充分的理由写这篇文章。还有一件事。
我希望使用BuildBot的专业社区变得更广泛,翻译手册并提供更多示例。谢谢大家的关注。祝你好运