Моето име е Евгений Черкин, я программист команды разработчиков в горнодобывающей компании Полиметал.
Приступая к любому крупному проекту начинаешь задумываться: «Какой же софт лучше использовать для его обслуживания?». IT-проект перед выпуском очередной версии проходит ряд этапов. Хорошо, когда цепочка этих этапов автоматизирована. Сам по себе автоматизированный процесс выпуска новой версии IT-проекта называется Континуирана интеграција. BuildBot для нас оказался хорошим помощником, реализующим этот процесс.
В этой статье я решил представить обзор возможностей BuildBot. На что способен этот софт? Как к нему подступиться и как выстроить с ним нормальные ЭФФЕКТИВНЫЕ РАБОЧИЕ ОТНОШЕНИЯ? Наш опыт вы можете применить и у себя, создав на своей машине рабочий сервис сборки и тестирования вашего проекта. содржина
Ранее на habr-e я встречал статьи о реализации Континуирана интеграција користење BuildBot. На пример, Оваа показалась мне наиболее информативной. Есть другой пример — поедноставно. Данные статьи можно приправить примером с мануалаИ овој вдогоночку, на английском языке. В купе получается неплохая отправная точка. Прочитав эти статьи, вы наверняка сразу захотите что-нибудь на BuildBot сделать.
Стоп! А кто-то вообще использовал его в своих проектах? Оказывается да, многу применили его в своих задачах. Можно найти примери користат BuildBot и в архивах кодов Google.
Так какова же логика людей, использующих Buildbot? Ведь есть другие инструменты: CruiseControl и Џенкинс. Отвечу так. Для большинства задач Џенкинс и правда будет достаточно. В свою очередь, BuildBot — более адаптивный, при этом задачи там решаются так же просто, как и в Џенкинс. Выбирать вам. Но раз уж мы ищем инструмент для развивающегося целевого проекта, то почему бы не выбрать тот, который позволит, отталкиваясь от простых шагов, получить систему сборки, имеющую интерактивность и уникальный интерфейс.
У тех, чей целевой проект написан на python, возникает вопрос: «Почему бы не выбрать систему интегрирования, в которой есть понятный интерфейс с точки зрения языка, используемого в проекте?». И тут самое время представить преимущества BuildBot.
Итак, наш «инструментальный квартет». Для себя я определил четверку особенностей BuildBot:
Это framework c открытым исходным кодом под лицензией GPL
Это использование python как инструмент конфигурирования и описания требуемых действий
Это возможность получать ответ со стороны машины, на которой происходит сборка
Это, наконец, минимальные требования к Хосту. Для развертывания требуется python и twisted, и не требуется виртуальная машина и java-машина.
2. Концепция во главе с BuildMaster
Центральное место в архитектуре распределения задач занимает BuildMaster. Он представляет из себя сервис, который:
отслеживает изменения в дереве исходников проекта
испраќа команды, которые следует выполнить сервису Worker для построения проекта и его тестирования
известува пользователей о результатах выполненных действий
BuildMaster конфигурируется через файл господар.cfg. Это файл лежит в корне BuildMaster. Позже я покажу, как этот корень создается. Сам по себе файл господар.cfg содержит в себе python — скрипт, использующий вызовы BuildBot.
Следующий наиболее важный объект BuildBot има име Работник. Этот сервис может быть запущен на другом хосте c другой OS, а может и на том, где BuildMaster. Также он может существовать в специально заготовленной виртуальной среде со своими пакетами и переменными. Данные виртуальные среды могут быть приготовлены при помощи python-утилит вроде vertualenv, venv.
BuildMaster транслирует команды каждому Работник-у, а тот, в свою очередь, их выполняет. То есть получается, что процесс построения и тестирования проекта может идти на Работник-е под управлением Windows и на другом Worker-е под управлением linux.
Сheckout исходных кодов проекта происходит на каждом Работник-е.
3. Инсталација
Итак, поехали. В качестве хоста я буду использовать Ubuntu 18.04. На нем я размещу одного BuildMaster-a и одного Работник-a. Но сначала потребуется установить python3.7:
Следующим шагом мы устанавливаем Twited и BuildBot, а так же пакеты позволяющие задействовать дополнительный функционал BuildBot-а.
/*Все что под sudo будет установленно для всех пользователей в директорию /usr/local/lib/python3.7/dist-packages*/
#На хосте который производит мониторинг Worker-ов
sudo pip install twisted #Библиотека twisted
sudo pip install buildbot #BuildMaster
#Дополнительный функционал
pip install pysqlite3 #Устанавливаем базу sqllite в учебных целях
pip install jinja2 #framework наподобие django, для web и для почтовых рассыллок
pip install autobahn #Web cокеты для связи BuildMaster->Worker
pip install sqlalchemy sqlalchemy-migrate #Для отображения схемы базы данных
#Для Web отображения BuildBot-a
pip install buildbot-www buildbot-grid-view buildbot-console-view buildbot-waterfall-view
pip install python-dateutil #Отображение дат в web
#На стороне хоста который непосредственно осуществляет сборку и тестирование
pip install buildbot-worker #Worker
#Дополнительный функционал
sudo pip install virtualenv #Виртуальная среда
4. Первые шаги
Время создать BuildMaster. Он будет у нас в папке /home/habr/master.
mkdir master
buildbot create-master master # Собственно сдесь и создаем
Следующий шаг. Создадим Работник. Он будет у нас в папке /home/habr/worker.
Кога трчате Работник, то по умолчанию он создаст в /home/habr/worker папку с названием проекта, который указан в господар.cfg. А в папочке с названием проекта он создаст директорию се изгради, и далее в неё будет делать исходот. Рабочим каталогом для Работник-а станет директория /home/habr/yourProject/build.
«Золотой» ключик
А теперь то, ради чего я писал предыдущий абзац: скрипт, который Господар потребует у Работник-а сделать удаленно в этой директории, не будет выполнен, поскольку у скрипта нет прав для запуска. Чтобы исправить ситуацию, потребуется ключик —umask=0o22, который накладывает запрет на запись в эту директорию, но права запуска оставит. А нам только это и нужно.
BuildMaster и Работник устанавливают между собой соединение. Случается, что оно обрывается и Работник некоторое время ожидает ответа от BuildMaster-а. Если ответа не последует, то подключение перезапускается. Ключ —keepalive=60 как раз и нужен для того, чтобы указать время, по прошествии которого се поврзете перезагружается.
5. Конфигурация. Пошаговый рецепт
Конфигурација BuildMaster ведется на стороне машины, где мы выполняли команду create-master. В нашем случае — это каталог /home/habr/master. Конфигурационный файл господар.cfg пока еще не существует, однако сама команда уже создала файл master.cmg.sample. Необходимо переименовать его в master.cfg.sample в господар.cfg
mv master.cfg.sample master.cfg
Откроем этот господар.cfg. И разберем то, из чего он состоит. А после этого попробуем сделать свой конфигурационный файл.
BuildmasterConfig — базовый словарь конфигурационного файла. Он должен быть обязательно задействован в конфигурационном файле. Для удобства использования в коде конфигурации вводится его псевдоним "в". Наслови клучеви в c[«keyFromDist»] являются фиксированными элементами для взаимодействия с BuildMaster. Под каждый ключ в качестве значения подставляется соответствующий объект.
На этот раз мы указываем BuildMaster-у список из Работник-ов. Сам Работник мы создавали над, што укажува you-worker-name и лозинка. Теперь их же надо указать вместо example-worker и помине .
По ключу change_source словаря c получаем доступ к списку, куда требуется положить объект, опрашивающий репозиторий с исходным кодом проекта. В примере используется Git репозиторий, который опрашивается с некоторой периодичностью.
Первый аргумент является путем к вашему репозиторию.
workdir представляет собой путь к папке, где на стороне Работник-а относительно пути /home/habr/worker/yourProject/build будет git хранить локальную версию репозитория.
гранка содержит конкретную ветку в репозитории, за которой следует следить.
pollInterval содержит число секунд, по истечению которых BuildMaster будет опрашивать репозиторий на наличие изменений.
Есть несколько методов отслеживать изменения в репозитории проекта.
Самый простой метод — это избирачки, который подразумевает, что BuildMaster периодически опрашивает сервер с репозиторием. В случае, если изврши отразил изменения в репозитории, то BuildMaster с некоторой задержкой создаст внутренний объект Промени и направит его в обработчик событий Распоредувачот, который и запустит шаги по сборке и тестированию проекта на Работник-е. Среди эти шагов будет указан ажурирање репозитория. Именно на Работник-е создастся локальная копия репозитория. Детали этого процесса будут раскрыты ниже в следующих двух разделах (5.4 и 5.5).
Еще более изящным методом отслеживания изменений в репозитории является прямая отправка сообщений от сервера, на котором он размещен, к BuildMaster-у об изменении исходных кодов проекта. В этом случае, как только разработчик сделает изврши, сервер с репозиторием проекта пошлет сообщение BuildMaster-у. А тот, в свою очередь, его перехватит создав объект PBChangeSource. Далее этот объект будет передан в Распоредувачот, который и активирует шаги по сборке проекта и его тестированию. Важная часть этого способа эта работа с кука-скриптами сервера в репозитории. В скрипте кука-а, отвечающего за обработку действий при изврши-е, необходимо вызвать утилиту sendchange и указать сетевой адрес BuildMaster-а. Указать нужно и сетевой порт, который будет слушать PBChangeSource. PBChangeSource, кстати, является частью BuildMaster-а. Это метод потребует права admin-a на сервере, где расположен репозиторий проекта. Предварительно потребуется сделать backup репозитория.
распоредувачи – это элемент, который выступает триггером, запускающим всю цепочку сборки и тестирования проекта.
Те изменения, которые были зафиксированы change_source, преобразовались в процессе работы BuildBot-a в объект Промени и теперь каждое Sheduler на их основе строит запросы на запуск процесса сборки проекта. Однако он определяет и то, когда эти запросы передать дальше в очередь. Объект Градител хранит у себя очередь запросов и отслеживает состояние текущей сборки на отдельном Работник-e. Градител существует и на BuildMaster-e и на Работник-e. Он же посылает с BuildMaster-а на Работник-а уже конкретный се изгради — серию шагов, которую следует выполнить.
Мы видим, что в текущем примере таких распоредувачи создается 2 штуки. Причем, каждая имеет свой тип.
SingleBranchScheduler – один из самых популярных классов расписания. Он наблюдает за одной веткой и срабатывает по зафиксированному изменению в ней. Когда он видит изменения, то может отложить отправку запроса на построение (отложить на период, указанный в специальном параметре treeStableTimer). ВО името задается имя расписания, которое будет отображаться в BuildBot-web-интерфейсе. В ChangeFilter задается фильтр, пройдя который изменения в ветке побуждают расписание послать запрос на построение. В builderNames указывается имя градител-a, которое мы зададим чуть позже. Имя в нашем случае будет то же, что и имя проекта: yourProject.
ForceScheduler весьма простая штука. Этот вид расписания срабатывает по щелчку мыши через BuildBot-web-интерфейс. Параметры имеют ту же суть, что и в SingleBranchScheduler.
P.S. №3. Вдруг пригодится Периодично — это расписание, которое срабатывает с определенной фиксированной по времени периодичностью. Выглядит вызов его примерно так
periodicBuildTimer задает время этой периодичности в секундах.
BuildFactory создает конкретный се изгради, который потом градител отсылает на Работник. Во BuildFactory указываются шаги, которые следует выполнить Работник-у. Шаги добавляются при помощи вызова метода addStep
Первый добавленный шаг в этом примере — git clean -d -f -f –x, тогаш git исход. Эти действия заложены в параметре метод, который наглядно не указан, но подразумевает значение по умолчанию свежо. Параметар mode=’incremental’ говорит о том, что файлы из директории, куда делается chechout, при этом отсутствующие в репозитории, остаются нетронутыми.
Второй добавленный шаг — это вызов скрипта судење c параметром Здраво на стороне Работник-а из директории /home/habr/worker/yourProject/build c переменной окружения PATHONPATH=… Таким образом, вы можете писать свои скрипты и выполнять их на стороне Работник-a через шаг util.ShellCommand. Данные скрипты можно положить прямо в репозиторий. Тогда при chechout-е они будут попадать в /home/habr/worker/yourProject/build. Однако тогда есть два «но»:
Работник должен быть создан с ключем —umask для того, чтобы он не блокировал права на выполнения после исходот-а.
на git push-е этих скриптов необходимо указать свойство exacutable, чтобы потом при chechout-e права на выполнение скрипта Git не потерял.
О том, что такое Градител было рассказано тука. Сейчас я поподробнее расскажу о том, как его создать. BuilderConfig является конструктором градител. Таких конструкторов в c[‘builders’] можно задать несколько, поскольку это лист объектов градител типа. Сейчас чуть перепишем пример от BuildBot, приблизив его к нашей задаче.
името задает имя градител-a. Здесь мы назвали его yourProject. Это значит, что на Работник-е будет создан этот самый путь /home/habr/worker/yourProject/build. Sheduler отыскивает градител как раз по этому имени.
workernames содержит лист Работник-ов. Каждый из которых должен быть добавленн в c[‘workers’].
фабрика — конкретный се изгради, с которым ассоциирован градител. Он пошлет объект се изгради на Работник для выполнения всех шагов, входящих в состав этого се изгради-а.
6. Пример собственной конфигурации
Вот архитектура примера проекта, которую я предлагаю реализовать через BuildBot .
В качестве системы контроля версиями будем использовать svn. Сам репозиторий будет находится в некоем облаке. Вот адрес этого облака svn.host/svn/yourProject/trunk. В облаке под svn есть учётка username: корисникот, passwd: лозинка. Скрипты, которые представляют из себя шаги се изгради-a будут также лежать в ветке svn, в отдельной папке buildbot/worker_linux. Эти скрипты лежат в репозитории с сохраненным свойством извршна.
BuildMaster и Работник работают на одном хосте project.host .BuildMaster хранит свои файлы в папке /home/habr/master. Работник же хранит по следующему пути /home/habr/worker. Связь процессов BuildMaster-а и Работник-а ведется через 4000 порт по протоколу BuildBot-a, то есть ‘pb’ протокол.
Целевой проект целиком написан на python-е. Задача отследить его изменения, создать executable файл, сгенерировать документацию, провести тестирование. В случае failure нужно всем разработчикам отослать сообщение на почту о том, что есть неудачно выполненное действие.
Web отображение BuildBot мы подключим на 80 порт для project.host. Apatch ставить не обязательно. В составе библиотеки извртени уже присутствует web сервер, BuildBot его использует.
Для хранения информации внутреннего назначения для BuildBot ќе користиме квлит.
Для почтовой рассылки нужен хост smtp.your.domain — на нем разрешена отправка писем с почты [заштитена по е-пошта]без аутентификации. Так же на хосте ‘SMTP ‘ протокол слушается на посту 1025.
Задействованных лиц в процессе двое: admin и корисникот. admin администрирует BuildBot. user является лицом, совершающим изврши-ы.
Exacutable файл генерируется через pyinstaller. Документация генерируется через doxygen.
Для данной архитектуры я написал вот такой господар.cfg:
господар.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="[email protected]",
sendToInterestedUsers=True,
lookup="your.domain",
relayhost="smtp.your.domain",
smtpPort=1025,
mode="warnings",
extraRecipients=['[email protected]'],
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-а и Работник-a. Затем вставить этот файл господар.cfg в /home/habr/master.
Следующим шагом требуется запустить службу BuildMasterа
sudo buildbot start /home/habr/master
Затем запустить службу Работник-a
buildbot-worker start /home/habr/worker
Готово! Теперь Buildbot будет отслеживать изменения и срабатывать по изврши-у в svn, выполняя шаги сборки и тестирования проекта с вышеуказанной архитектурой.
Ниже я распишу некоторые особенности вышеуказанного master.cfg.
6.1 На пути к своему master.cfg
Во время написания своего господар.cfg будет совершено немало ошибок, потому потребуется чтение log-файла. Он храниться как на BuildMaster-e c абсолютным путем /home/habr/master/twistd.log, так и на стороне Работник-a с абсолютным путем /home/habr/worker/twistd.log. По мере чтения ошибки и ее исправления потребуется перезагрузка службы BuildMaster-a. Вот как это делается:
Для начала взглянем на svn_poller. Это все тот же интерфейс, регулярно опрашивающий репозиторий раз в минуту. В данном случае svn_poller обращается только к ветке багажникот. Загадочный параметр split_file=util.svn.split_file_alwaystrunk задает правила: как разбивать структуру папок svn на ветки. Он же предлагает им относительные пути. В свою очередь split_file_alwaystrunk упрощает процесс, говоря о том, что в репозитории только багажникот.
В Распоредувачи посочено ChangeFilter, который видит Никој и ассоциирует с ним ветку багажникот по заданной ассоциации через split_file_alwaystrunk. Реагируя на изменения в багажникот, запускает градител c именем yourProject.
својства здесь нужен для того, чтобы админ получал рассылку у результатах сборки и тестирования как владелец процесса.
Чекор се изгради-a исходот способен делать полное удаление любых файлов, лежащих в локальной версии репозитория Работник-а. A затем делать полный svn ажурирање. Режим настроен через параметр mode=full, method=fresh. Параметар haltOnTailure говорит о том, что если svn ажурирање будет выполнен с ошибкой, то весь процесс сборки и тестирования следует приостановить, так как дальнейшие действия не имеют смысла.
6.3 Вам письмо: reporters уполномочен заявить
новинарите — это сервис рассылки уведомлений на почту.
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="[email protected]",
sendToInterestedUsers=True,
lookup="your.domain",
relayhost="smtp.your.domain",
smtpPort=1025,
mode="warnings",
extraRecipients=['[email protected]'],
messageFormatter=reporters.MessageFormatter(
template=template_html,
template_type='html',
wantProperties=True,
wantSteps=True)
)
c['services'] = [sendMessageToAll]
MailNotifier использует почту для рассылки уведомлений.
template_html задает шаблон текста для рассылки. Для создания разметки используется html. Он модифицирован движком џинџа2 (можно сравнить с django). BuildBot имеет набор переменных, значения которых подставляются в шаблон в процессе формирования текста сообщения. Эти переменные вписаны в {{ двойные фигурные скобки }}. Так, например, резиме выводит статус выполненных операций, то есть success или failure. А проекти выведет yourProject. Так, при помощи управляющих команд в џинџа2, переменных BuildBot-а и средств форматирования строк python можно создать вполне информативное сообщение.
MailNotifier содержит следующие аргументы.
fromaddr – адрес, с которого всем будет приходить рассылка.
sendToInterestedUsers=True отсылает сообщение владельцу и пользователю, который сделал изврши.
пребарување — суффикс, который надо добавить к именам пользователей, получающим рассылку. Так admin как пользователь получит рассылку по адресу [заштитена по е-пошта].
relayhost задает имя хоста, на котором открыт сервер SMTP, На smptPort задает номер порта который слушает SMTP сервер.
mode=«warning» говорит, что рассылку нужно делать только в случае наличия хотя бы одного шага се изгради-а, который закончился со статусом failure или warning. В случае success рассылку делать не требуется.
extraRecipients содержит список лиц, кому следует сделать рассылку помимо владельца и лица, осуществившего изврши.
messageFormatter является объектом, задающим формат сообщения, его шаблон, и набор переменных доступных из џинџа2. Такие параметры, как wantProperties=True и wantSteps=True задают этот набор доступных переменных.
с[‘services’]=[sendMessageToAll] предоставляет список сервисов, среди которых и будет наш новинар.
Мы сделали это! Мои поздравления
Мы создали собственную конфигурацию и увидели функционал, на который способен BuildBot. Этого, думаю, достаточно для того, чтобы понять, нужен ли этот инструмент для создания вашего проекта. Он вам интересен? Он вам пригодится? С ним удобно работать? Тогда я писать эту статью не зря.
И еще. Хотелось бы, чтобы профессиональное сообщество, использующее BuildBot, стало шире, мануалы переводились, и примеров становилось еще больше.