Введение
Сложно представить современную разработку без Continuous Integration. Многие компании выпускают по нескольку релизов в день и прогоняют тысячи тестов. Со времен Jenkins и Travis CI на рынке появилось много самых разнообразных инструментов. Большинство из них работают по модели SaaS — вы платите фиксированную плату за использование сервиса, или за количество пользователей.
Но использование hosted платформ не всегда возможно, например, если нельзя передавать код приложения, или не хочется зависеть от внешних сервисов. В таком случае выручают системы, которые можно установить на своих серверах (self-hosted). Бонусом вы имеете полный контроль над ресурсами и можете масштабировать их согласно вашим потребностям используя, к примеру, amazon ec2.
В этой статье представлен личный опыт использования нескольких opensource self-hosted continuous integration систем. Если вы использовали другие системы, расскажите об этом в комментариях.
Основные понятия
Основой любого CI является билд (build) — единичная сборка вашего проекта. Билд может собираться по различным триггерам — пуш в репозиторий, pull-request, по расписанию. Билд состоит из набора задач (jobs). Задачи могут выполняться как последовательно, так и параллельно. Набор задач задается перечислением всех задач или матрицей билда (build matrix) — характеристиками, по которым происходит разделение. Например, указанием версий языка программирования и переменных окружения — для каждой версии языка и каждого значения переменной будет создана своя задача.
В некоторых ci системах также есть конвейер задач (pipeline) — задачи объединяются в группы (stage), все задачи в текущей группе исполняются параллельно, следующая группа выполняется только если предыдущая группа завершилась успешно. Например, конвейер test — deploy: если все задачи в test завершились успешно, то можно запускать задачи из группы deploy.
Для эффективной работы ci важно наличие кэша — данных, которые используются для ускорения сборки. Это могут быть apt-пакеты, кэш npm, composer. Без кэша при запуске каждой задачи нужно будет заново скачивать и устанавливать все зависимости, что может занять времени больше, чем сам прогон тестов. Чем ближе расположен кэш к серверам, на которых выполняются задачи, тем лучше, например, если вы используете amazon ec2, то хорошим вариантом будет хранить кэш в amazon s3.
При выполнении билда могут генерироваться артефакты — результаты сборки, отчеты о чистоте кода, логи. CI-система, позволяющая просматривать и скачивать эти артефакты, существенно облегчает жизнь.
Если у вас большой проект с большим количеством одновременно запущенных задач, то вам не обойтись без масштабирования. Масштабирование бывает ручным и автоматическим. При ручном масштабировании вы сами запускаете и останавливаете runner-ы на свободных серверах. В случае автоматического масштабирования система сама решает, нужно ли создавать новые виртуальные машины и в каком количестве. Разные ci-системы поддерживают разных провайдеров — обычно это amazon, google compute, digital ocean и т.д.
Важным является то, как система запускает команды, указанные в конфигурации билда (executors). Есть несколько способов: непосредственное выполнение (на хосте, где запущен runner), выполнение в виртуальной машине, в docker-контейнере, через ssh. У каждого способа есть особенности, которые нужно учитывать при выборе ci-системы, например, при запуске задачи в docker-контейнере отсутствует сессия и терминал, из-за чего некоторые вещи не получится протестировать. А при выполнении на хосте не забывать о очистке ресурсов после окончания выполнения — удаления данных из бд, docker-образов и т.д.
Наконец, есть параметры, которые не критически важные, но делают работу с ci приятнее. Вывод лога — работает ли он в realtime режиме, или с каким-то интервалом? Можно ли прервать билд в случае проблем? Можно ли посмотреть конфигурацию билда и задачи?
Drone
Drone — система непрерывной интеграции, основанная на docker-контейнерах. Написана на языке Go. Текущая версия — 0.4, версия 0.5 находится в бете. В обзоре рассматривается версия 0.5.
Drone умеет работать с большим количеством git-репозиториев — GitHub, Bitbucket, Bitbucket Server, GitLab, Gogs. Конфигурация билдов настраивается в файле .drone.yml в корне репозитория.
Билд состоит из нескольких шагов, каждый шаг исполняется параллельно в отдельном docker-контейнере. Матрица билда задается за счет переменных окружения. Возможно использование сервис-контейнеров — например, если вы тестируете веб-приложение, которое работает с базой данных, то нужно задать docker-образ БД в секции services, и она автоматически будет доступна из build-контейнера. Можно использовать любые образы docker.
Drone состоит из drone server и drone agent. Drone server выполняет роль координатора, а один или несколько drone agent запускают билды. Масштабирование осуществляется за счет запуска дополнительных drone agent-ов. Возможности использовать облачные ресурсы для автозапуска агентов нет. Встроенной поддержки кэша не предусмотрено (есть сторонние плагины для загрузки и сохранения кэша на s3 хранилища).
Команды, указанные в билде, выполняются непосредственно в docker-контейнере интерпретатором sh, что создает проблемы, если нужно выполнять сложные команды с условной логикой.
Gitlab CI
Gitlab CI является частью проекта Gitlab — self-hosted аналога Github. Gitlab написан на ruby, а gitlab runner — на Go. Текущая версия gitlab — 8.15, gitlab runner — 1.9.
Поскольку Gitlab CI интегрирован с gitlab, то он использует только gitlab как репозиторий. Можно зеркалировать сторонние репозитории на gitlab, но на мой взгляд, это не очень удобно. Билд организован по принципу конвейера. Можно настраивать тип запуска задач — автоматически или вручную из веб-интерфейса.
Gitlab CI состоит из веб-интерфейса (координатора) и runner-ов. Координатор распределяет задачи по runner-ам, которые их выполняют. Есть большой выбор executors — shell, docker, docker-ssh, ssh, virtualbox, kubernetes. Лог билда не real-time — веб-интерфейс периодически опрашивает сервер, если появилась новая часть лога, то она добавляется в конец.
Имеется встроенная поддержка кэша, в качестве хранилища может использоваться любое s3-совместимое хранилище. Есть артефакты — можно просматривать отдельные файлы и скачивать артефакт целиком из веб-интерфейса.
Работа с облачными ресурсами организована с помощью docker mashine. При поступлении запроса на новый билд, если нет свободной машины, docker mashine создаст новую машину и запустит билд на ней. При этом образы, требуемые для билда, придется скачать заново, поэтому gitlab рекомендует поднять отдельный docker registry, который был бы в той же сети, что и провайдер docker mashine.
SimpleCI
SimpleCI — система непрерывной интеграции, которая была написана для максимально эффективного использования ресурсов. Frontend написан на php (Symfony3, es6), backend — на java. Текущая версия — 0.6, ведется активная разработка.
SimpleCI поддерживает github и gitlab репозитории. Билд, также, как и в gitlab, организован по принципу конвейера. Если все задачи в рамках одной стадии завершились успешно, то запускается следующая стадия.
Поддерживается работа с кэшэм. Кэш заливается в хранилище только, если в рамках задачи кэш-файлы изменились. Реализована работа с двумя типами хранилищ — s3-совместимым и google storage.
Билд выполняется путем запуска docker-контейнеров, подключения к build-контейнеру по ssh и запуску build-скрипта. Лог билда отображается в реальном времени (с помощью websockets и centrifugo).
Есть возможность автомасштабирования путем использования ресурсов облачных провайдеров (пока только google compute engine). При настройке масштабирования нужно указать snapshot, который будет использоваться при создании виртуальной машины. Это позволяет создать snapshot с необходимыми docker-образами, чтобы не загружать из каждый раз при создании новой машины. Поддержки артефактов пока нет.
Заключение
В обзоре представлено несколько self-hosted open source систем непрерывной интеграции. Кроме рассмотренных, также есть много hosted, коммерческих и открытых систем. Выбирая из всего многообразия CI-систем, обращайте внимание на то, что нужно вам, и тесты скажут вам спасибо.
Ссылки
- Drone
- Gitlab CI
- SimpleCI
- Jenkins
- awersome ci — список ci систем, средств для тестирования и деплоя
Комментарии (17)
m1kola
03.01.2017 13:50Встроенной поддержки кэша не предусмотрено
Вы в этом уверены? Поддержки s3 из коробки нет, но, насколько я помню, в конфиге есть секция
cache
в которой можно задать директории, которые нужно сохранять между билдами. Например для сохраненияnode_modules
или виртуального окружения Python.lewbor
03.01.2017 15:30Для версии 0.5 — http://readme.drone.io/questions/how-to-cache-artifacts/
m1kola
03.01.2017 19:41В последний раз, когда я пробовал Drone 0.5,
cache
секция работала как в версии 0.4, но с учетом нового синтаксиса версии 0.5. Сейчас в документации для 0.5 я ничего про эту секцию конфига не нашел. Возможно решили выкинуть из ядра.
pronvit
04.01.2017 06:30Я использую QuickBuild для сборки проектов сразу под три платформы. Перепробовал все найденные решения. Большинство не имеет агентов под винду; Jenkins — страшный и сложный. Вероятно, при должно терпении, там можно найти плагины и все настроить, но я два раза пробовал и бросал. TeamCity — подходит под мои задачи, но не очень гибкий и тяжелый в плане ресурсов сервера. А у QuickBuild нет проблем с поддержкой трех систем и довольно легко было настроить, чтобы собирать три бинарника из одного проекта, а потом делать из них один архив. И очень гибкий с поддержкой скриптов во всех полях.
steban
04.01.2017 06:30Оно в ядре и не нужно. Это можно быстренько сделать на коленке. Можно использовать s3 или просто машинку с openssh. В моем случае этим целям служит отдельный контейнер с caddy (+ модуль upload)
pipeline: cache_get: image: ..../cache path: /drone/.m2 retrieve: m2 build: image: .../maven commands: - mvn install -q ..... cache_put: image: .../cache path: /drone/.m2 store: m2
образ cache содержит простой скрипт:
#!/bin/sh store() { cd "$1" if tar cz .| curl -u $USER:$PASS -T - $URL/cache/$2.tar.gz then echo "$2 stored successfully" fi exit 0 } retrieve() { if curl -u $USER:$PASS $URL/cache/$2.tar.gz | tar zx -C $1 then echo "$2 retrieved successfully" fi exit 0 } if [ ! -d "$PLUGIN_PATH" ]; then mkdir $PLUGIN_PATH fi if [ -n "$PLUGIN_STORE" ]; then store $PLUGIN_PATH $PLUGIN_STORE exit 0 fi if [ -n "$PLUGIN_RETRIEVE" ]; then retrieve $PLUGIN_PATH $PLUGIN_RETRIEVE exit 0 fi
steban
12.01.2017 23:53А вот еще решение с хранением кеша на выполняющем хосте: https://github.com/Drillster/drone-volume-cache
Но оно требудет привилегированного контейнера и подписанного drone.yml
iroln
Почему Jenkins не вошёл в обзор? Вообще, честно говоря, обзор ни о чём. Например, нам нужен CI-сервер для кроссплатформенного C++ приложения с кучей зависимостей. И как ваш обзор нам поможет в выборе?
На самом деле мы давно пользуемся какой-то древней версией Jenkins и нам хватает, но вот лично мне хотелось бы узнать об альтернативных open source решениях, хотя сомневаюсь, что среди всех этих модных CI, основанных на docker-контейнерах, найдётся что-то удобнее и гибче чем наш дубовый Jenkins.
kazar
не пробовали обновлять софт? :) 2.0 jenkins очень даже гибкий, нынче пайплайны в тренде https://jenkins.io/doc/book/pipeline/ Контейнеры (и еще кучу всего) он тоже умеет, например https://wiki.jenkins-ci.org/display/JENKINS/Docker+Slaves+Plugin
gunya
пайплайнам сто лет в обед — в 2.0 их просто включили в стандартную поставку, плюс заопенсорсили Pipeline Stage View
gunya
Jenkins — эталон гибкости в Open Source CI. Drone и Gitlab CI — в разы проще для освоения, но и умеют в разы меньше — весь их функционал можно реализовать на Jenkins абсолютно без проблем.
lewbor
Что умеет Jenkins, чего не умеет, например, Gitlab CI?
gunya
— Копирование артефактов от других сборок. Есть репозиторий с библиотекой, есть репозиторий с основным приложением — нужно скопировать последнюю собранную библиотеку.
— Build Parameters и ручной ребилд — нужно собрать инсталлятор, в который войдут несколько приложений, которые прошли ручное тестирование. При этом последний успешный артефакт нас не устраивает — мы выпускаем патч на софт полугодичной давности.
— Любая логика — если сборка для тега XXX есть — скопировать ее артефакты, если ее нет — запустить сборку и скопировать ее артефакты.
Плюс я не уверен, что в Gitlab CI есть matrix builds (собрать под Windows, Linux, OSX пакеты example, example-debug, example-some-feature, при этом под Windows не собирать example-debug, а под OSX не собирать example-some-feature). Естественно, если речь про C++ проект — надо все собирать под Windows, Linux и OSX соответственно.
lewbor
В Gitlab CI обещают улучшить работу с артефактами — можно будет загружать артефакты от предыдущих задач в конвейере, наверное, будет апи, с помощью которого можно будет делать многое из того, что вы описываете. Ручного запуска билдов, насколько я знаю, нет. А build matrix есть, но она задается вручную перечислением задач.
С другой стороны, в Jenkins довольно тяжело работать с docker. А без него сложно обеспечить изоляцию билдов — например, на одном воркере тестировать проект с разными версиями python и mysql одновременно. И с автоматическим созданием воркеров в облаках непросто.
gunya
> С другой стороны, в Jenkins довольно тяжело работать с docker.
Я всеми руками за использование docker в CI, и в Jenkins есть два очень простых и правильных способа работы с Docker:
— Docker Custom Build Environment
— Docker Pipeline Plugin
Для сборки есть Docker Build and Publish Plugin
> И с автоматическим созданием воркеров в облаках непросто.
Jenkins умеет автоматически поднимать слейвы в облаках по требованию, например EC2 Plugin. Хотя я привык создавать машины руками и накатывать окружение (JVM и docker) через puppet.
aenesterov
Еще есть GoCD by ThoughtWorks. Это уже Continuous Delivery. OpenSource. И позволяет создавать более гибкие пайплайны в сравнении с Jenkins 2.