Опыт использования self-hosted continuous integration систем

    Введение


    Сложно представить современную разработку без 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
      +10

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


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

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

        не пробовали обновлять софт? :) 2.0 jenkins очень даже гибкий, нынче пайплайны в тренде https://jenkins.io/doc/book/pipeline/ Контейнеры (и еще кучу всего) он тоже умеет, например https://wiki.jenkins-ci.org/display/JENKINS/Docker+Slaves+Plugin
          0
          пайплайнам сто лет в обед — в 2.0 их просто включили в стандартную поставку, плюс заопенсорсили Pipeline Stage View
          0
          Jenkins — эталон гибкости в Open Source CI. Drone и Gitlab CI — в разы проще для освоения, но и умеют в разы меньше — весь их функционал можно реализовать на Jenkins абсолютно без проблем.
            +1
            Что умеет Jenkins, чего не умеет, например, Gitlab CI?
              +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 соответственно.
                0
                В Gitlab CI обещают улучшить работу с артефактами — можно будет загружать артефакты от предыдущих задач в конвейере, наверное, будет апи, с помощью которого можно будет делать многое из того, что вы описываете. Ручного запуска билдов, насколько я знаю, нет. А build matrix есть, но она задается вручную перечислением задач.
                С другой стороны, в Jenkins довольно тяжело работать с docker. А без него сложно обеспечить изоляцию билдов — например, на одном воркере тестировать проект с разными версиями python и mysql одновременно. И с автоматическим созданием воркеров в облаках непросто.
                  +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.
            0
            хотелось бы узнать об альтернативных open source решениях, хотя сомневаюсь, что среди всех этих модных CI, основанных на docker-контейнерах, найдётся что-то удобнее и гибче чем наш дубовый Jenkins


            Еще есть GoCD by ThoughtWorks. Это уже Continuous Delivery. OpenSource. И позволяет создавать более гибкие пайплайны в сравнении с Jenkins 2.
            +2
            СoncourseCI ещё стоит упомянуть
              0
              Встроенной поддержки кэша не предусмотрено

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

                0
                  0

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

                    0
                    Промахнулся с веткой. мой ответ про кеш ниже.
                0
                Я использую QuickBuild для сборки проектов сразу под три платформы. Перепробовал все найденные решения. Большинство не имеет агентов под винду; Jenkins — страшный и сложный. Вероятно, при должно терпении, там можно найти плагины и все настроить, но я два раза пробовал и бросал. TeamCity — подходит под мои задачи, но не очень гибкий и тяжелый в плане ресурсов сервера. А у QuickBuild нет проблем с поддержкой трех систем и довольно легко было настроить, чтобы собирать три бинарника из одного проекта, а потом делать из них один архив. И очень гибкий с поддержкой скриптов во всех полях.
                  0
                  Оно в ядре и не нужно. Это можно быстренько сделать на коленке. Можно использовать 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
                  

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

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое