Введение


Сложно представить современную разработку без 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-систем, обращайте внимание на то, что нужно вам, и тесты скажут вам спасибо.

Ссылки


Поделиться с друзьями
-->

Комментарии (17)


  1. iroln
    03.01.2017 12:27
    +10

    Почему Jenkins не вошёл в обзор? Вообще, честно говоря, обзор ни о чём. Например, нам нужен CI-сервер для кроссплатформенного C++ приложения с кучей зависимостей. И как ваш обзор нам поможет в выборе?


    На самом деле мы давно пользуемся какой-то древней версией Jenkins и нам хватает, но вот лично мне хотелось бы узнать об альтернативных open source решениях, хотя сомневаюсь, что среди всех этих модных CI, основанных на docker-контейнерах, найдётся что-то удобнее и гибче чем наш дубовый Jenkins.


    1. kazar
      03.01.2017 15:21
      -1

      сомневаюсь, что среди всех этих модных CI, основанных на docker-контейнерах, найдётся что-то удобнее и гибче чем наш дубовый Jenkins

      не пробовали обновлять софт? :) 2.0 jenkins очень даже гибкий, нынче пайплайны в тренде https://jenkins.io/doc/book/pipeline/ Контейнеры (и еще кучу всего) он тоже умеет, например https://wiki.jenkins-ci.org/display/JENKINS/Docker+Slaves+Plugin


      1. gunya
        03.01.2017 15:30

        пайплайнам сто лет в обед — в 2.0 их просто включили в стандартную поставку, плюс заопенсорсили Pipeline Stage View


    1. gunya
      03.01.2017 15:25

      Jenkins — эталон гибкости в Open Source CI. Drone и Gitlab CI — в разы проще для освоения, но и умеют в разы меньше — весь их функционал можно реализовать на Jenkins абсолютно без проблем.


      1. lewbor
        04.01.2017 06:45
        +1

        Что умеет Jenkins, чего не умеет, например, Gitlab CI?


        1. gunya
          04.01.2017 14:20
          +1

          — Копирование артефактов от других сборок. Есть репозиторий с библиотекой, есть репозиторий с основным приложением — нужно скопировать последнюю собранную библиотеку.
          — 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 соответственно.


          1. lewbor
            04.01.2017 14:52

            В Gitlab CI обещают улучшить работу с артефактами — можно будет загружать артефакты от предыдущих задач в конвейере, наверное, будет апи, с помощью которого можно будет делать многое из того, что вы описываете. Ручного запуска билдов, насколько я знаю, нет. А build matrix есть, но она задается вручную перечислением задач.
            С другой стороны, в Jenkins довольно тяжело работать с docker. А без него сложно обеспечить изоляцию билдов — например, на одном воркере тестировать проект с разными версиями python и mysql одновременно. И с автоматическим созданием воркеров в облаках непросто.


            1. gunya
              04.01.2017 15:32
              +1

              > С другой стороны, в Jenkins довольно тяжело работать с docker.

              Я всеми руками за использование docker в CI, и в Jenkins есть два очень простых и правильных способа работы с Docker:
              Docker Custom Build Environment
              Docker Pipeline Plugin

              Для сборки есть Docker Build and Publish Plugin

              > И с автоматическим созданием воркеров в облаках непросто.

              Jenkins умеет автоматически поднимать слейвы в облаках по требованию, например EC2 Plugin. Хотя я привык создавать машины руками и накатывать окружение (JVM и docker) через puppet.


    1. aenesterov
      03.01.2017 23:15

      хотелось бы узнать об альтернативных open source решениях, хотя сомневаюсь, что среди всех этих модных CI, основанных на docker-контейнерах, найдётся что-то удобнее и гибче чем наш дубовый Jenkins


      Еще есть GoCD by ThoughtWorks. Это уже Continuous Delivery. OpenSource. И позволяет создавать более гибкие пайплайны в сравнении с Jenkins 2.


  1. w32blaster
    03.01.2017 12:49
    +2

    СoncourseCI ещё стоит упомянуть


  1. m1kola
    03.01.2017 13:50

    Встроенной поддержки кэша не предусмотрено

    Вы в этом уверены? Поддержки s3 из коробки нет, но, насколько я помню, в конфиге есть секция cache в которой можно задать директории, которые нужно сохранять между билдами. Например для сохранения node_modules или виртуального окружения Python.


    1. lewbor
      03.01.2017 15:30

      1. m1kola
        03.01.2017 19:41

        В последний раз, когда я пробовал Drone 0.5, cache секция работала как в версии 0.4, но с учетом нового синтаксиса версии 0.5. Сейчас в документации для 0.5 я ничего про эту секцию конфига не нашел. Возможно решили выкинуть из ядра.


        1. steban
          04.01.2017 19:03

          Промахнулся с веткой. мой ответ про кеш ниже.


  1. pronvit
    04.01.2017 06:30

    Я использую QuickBuild для сборки проектов сразу под три платформы. Перепробовал все найденные решения. Большинство не имеет агентов под винду; Jenkins — страшный и сложный. Вероятно, при должно терпении, там можно найти плагины и все настроить, но я два раза пробовал и бросал. TeamCity — подходит под мои задачи, но не очень гибкий и тяжелый в плане ресурсов сервера. А у QuickBuild нет проблем с поддержкой трех систем и довольно легко было настроить, чтобы собирать три бинарника из одного проекта, а потом делать из них один архив. И очень гибкий с поддержкой скриптов во всех полях.


  1. 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
    


    1. steban
      12.01.2017 23:53

      А вот еще решение с хранением кеша на выполняющем хосте: https://github.com/Drillster/drone-volume-cache
      Но оно требудет привилегированного контейнера и подписанного drone.yml