Совсем недавно гитлаб героически выкатил версию 8.0 своего конкурента гитхабу. Из интересного — движок continuous integration теперь встроен в платформу, а значит доступен в качестве бесплатного сервиса для всех желающих на gitlab.com. Совместно с бесплатными приватными репозиториями это делает облачный сервис гитлаб не только удобным местом для хранения кода, но также тестирования и деплоя. О последнем я и расскажу под катом.


Continuous integration — это не только запуск юнит тестов при пуше нового кода в репозиторий. Это еще и возможность делать сборки продуктов, публиковать их в сторы, на сайты и в другие каналы распространения. Облачная телефония voximplant использует javascript сценарии, которые размещаются в нашем облаке и выполняются по команде “снаружи” или при поступлении входящего звонка. Многие клиенты для работы со сценариями используют встроенный в админку текстовый редактор, что вполне подходит для простых случаев. Но при разработке и поддержке сложных облачных систем, к примеру телефонии Bitrix24, нужно что-то более серьезное.


Создавая voximplant мы решили не делать push-to-deploy как у heroku. У многих наших клиентов основной бизнес не связан с разработкой софта, и оставлять их один на один с git’ом не очень хорошо. Зато есть HTTP API с функцией “задеплоить сценарий”, который намекает понимающим людям что сценарии можно хранить на gitlab и деплоить с помощью shell скрипта и curl. Большинство клиентов так и делает, но у подхода есть серьезный недостаток: скрипт нужно не забыть вызвать. Более того, вызывать его надо только если код был запушен в production ветку. И только после того, как прошли тесты. Вообще много способов ошибиться.


Настройка continuous integration в gitlab



По умолчанию continuous integration в гитлабе выключено и необходимо его включить в настройках:



После включения в левом меню настроек проекта появляется несколько новых пунктов, самый интересный для нас — это «runners». Continuous integration в гитлабе работает следующим образом:

  1. Вы делаете push в репозиторий
  2. Если в корне проекта есть файл .gitlab-ci.yml, то гитлаб понимает что для этого проекта будет использоваться continuous integration.
  3. Гитлаб ищет запущенный runner, подключенный для этого или для любого проекта. Runner — это приложение, которое обычно запускают на отдельном компьютере и которое будет собственно осуществлять continuous integration: прогонять тесты, собирать исполняемые файлы, осуществлять деплой. Можно запустить свой runner, к примеру на маке чтобы собрать приложение для iOS. Можно использовать “gitlab public runner”, но они не то чтобы очень безопасны и входящие очереди задач у них обычно многочасовые.
  4. Гитлаб передает yaml файл runner’у, который обновляет исходники в своем репозитории и выполняет команды, описанные в этом файле. Команды могут быть как простые, к примеру сделать деплой сценария в облако voximplant. Так и сложные: запуск docker контейнера, сборка в нем проекта, запуск тестов и так далее.
  5. После выполнения скриптов runner рапортует обратно гитлабу результаты, которые можно посмотреть рядом с соответствующим коммитом.


Установка gitlab ci runner


Для нашего примера мы запустим runner на машине разработчика. Инструкции по установки для windows/linux/osx доступна на официальном сайте, после установки мы получаем в свое распоряжение command line утилиту gitlab-ci-multi-runner. Запущенный runner подключается к гитлабу и ждет задачи на сборку. Но как гитлаб узнает, какие задачи какому runner’у давать? Чтобы “привязать” runner к своему аккаунту и проекту (или нескольким проектам) необходимо вызвать gitlab-ci-multi-runner с ключем register и ввести параметры подключение: url гитлаб (так как гитлаб может быть развернут локально в вашей сети) и токен регистрации, который, собственно, и определяет аккаунт/проекты:



Зарегистрированный runner запускается командой gitlab-ci-multi-runner run и ждет задачу от гитлаба. С помощью ключей командной строки install и start runner можно зарегистрировать в системе как сервис, чтобы он автоматически стартовал после перезагрузки операционной системы.

Конфигурация continuous integration для деплоя


Как я уже писал, задачи continuous integration описываются в файле .gitlab-ci.yml который необходимо разместить в корне проекта. Редкоземельный синтаксис YAML является как-бы-человекочитаемой альтернативой JSON’у, документация доступна на официальном сайте. Конфигурационный файл для деплоя проекта в voximplant будет максимально простым, все что нам нужно — это сделать один вызов HTTP API как описано в нашей документации. Если исходить из предположения, что runner выполняется на компьютере где установлен curl, а код сценария находится в файле scenario.js, то конфигурационный файл для деплоя будет выглядеть следующим образом (Упрощенный пример. Настоящий побольше будет, к примеру api_key имеет смысл вынести в переменную окружения, см. комментарий nmike):

before_script:
  - npm install
stages:
  - deploy
deploy:
  script:
  - curl -X POST "https://api.voximplant.com/platform_api/SetScenarioInfo/?account_id=1&api_key=2&required_scenario_name=foo" --data-urlencode scenario_script@scenario.js


В curl используется синтаксический сахар нашего API, которое может принимать аргументы как в компоненте query передаваемого url, так и в body http запроса.

Чтобы continuous integration заработал достаточно сделать push в репозиторий: гитлаб обнаружит файл .gitlab-ci.yml, найдет подключенный runner, передаст ему содержимое этого файла, runner обновит свою копию репозитория и запустит скрипт деплоя, который отгрузит исходный код в наше облако.

Вопросы, уточнения, комментарии? Gitlab vs Jenkins vs Bamboo vs Teamcity?

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


  1. arren
    03.11.2015 12:09
    +2

    Вкусно, но рецепт можно сделать так, чтобы деплой делался только при пуше (или аппруве мерж реквеста) в отдельную ветку, типа deploy или release, или еще как-то обозначающую, что это именно в релиз, а все остальные ветки, и даже теги, тестировать на других раннерах. Мастер, к примеру, можно выкатывать на тестовую среду, если таковая имеется.


    1. abcdmitry
      04.11.2015 06:16

      Это настраивается на уровне .gitlab-ci.yml — директивы only и except в описании задачи doc.gitlab.com/ci/yaml/README.html


      1. arren
        04.11.2015 14:32

        Спасибо, но это был не вопрос. По предложенной схеме мы работаем.


  1. mickvav
    03.11.2015 20:27
    +1

    а если мы сам yuml-файлик пушим, оно как его тестит?


    1. eyeofhell
      03.11.2015 20:40

      Не понял вопроса. «Оно» и «Его» — это кто такие? О_О


    1. nmike
      04.11.2015 01:03

      Тестит сам файлик? Вот тут в самом низу есть

      Validate the .gitlab-ci.yml

      Each instance of GitLab CI has an embedded debug tool called Lint. You can find the link to the Lint in the project's settings page or use short url /lint.


      1. eyeofhell
        04.11.2015 07:22

        Нужно добавить в .yaml файл вызов /lint с указанием этого файла.


  1. nmike
    04.11.2015 01:11
    +1

    — curl -X POST «api.voximplant.com/platform_api/SetScenarioInfo/?account_id=1&api_key=2&required_scenario_name=foo» --data-urlencode scenario_script@scenario.js
    вот тут вы предлагаете приватные данные прям в репозиторий пушить? так нельзя делать.
    Для этого есть Variables
    Storing API keys

    In GitLab CI 7.12 a new feature was introduced: Secure Variables. Secure Variables can added by going to Project > Variables > Add Variable. This feature requires gitlab-runner with version equal or greater than 0.4.0. The variables that are defined in the project settings are send along with the build script to the runner. The secure variables are stored out of the repository. Never store secrets in your projects' .gitlab-ci.yml. It is also important that secret's value is hidden in the build log.


    1. eyeofhell
      04.11.2015 07:23

      Согласен. Увы, если в статье писать вообще все что в настоящем ci делается — это будет wall of text, который никто никогда не будет читать :)


  1. Monnoroch
    04.11.2015 16:19
    +1

    Я столкнулся с проблемой, что когда я делаю пуллреквест, тесты запускаются только на последнем коммите пуллреквеста, что провоцирует методологию разработки «сделай как-нибудь, а потом допили до зеленой кнопочки».
    Может, кто-то смог это решить?


    1. eyeofhell
      04.11.2015 16:49

      Ммм… Ну вообще DVCS именно так работает — мы коммитим-коммитим-коммимтим локально, а когда оно все готово и собирается — пушим и оно делает тест по последнему коммиту. Промежуточные как бы показывают процесс работы, оно и не должно собираться/тестироваться. Если я правильно понял вопрос, конечно :)


      1. Monnoroch
        04.11.2015 17:05

        С моей точки зрения, каждый коммит должен быть (to the best of developers knowledge) рабочим чекпоинтом в жизни приложения. Все промежуточные нерабочие коммиты сквошатся в кошерные рабочие во время создания пуллреквеста.
        Собственно, это следствие названия continious deployment. Если бы только некоторые коммиты представляли собой рабочие версии, deployment был бы не continious а какой-то discrete что-ли.


        1. eyeofhell
          04.11.2015 17:06

          К этому есть два подхода — сквошить или не сквошить. Я уже старый, память плохая, большие коммиты читаю с трудом. Так что я за то, чтобы не сквошить — коммиты меньше, читать проще, комментарии к коммитам помогают.


          1. Monnoroch
            04.11.2015 17:10

            Гранулярность коммитов — это ортогональный вопрос, я не предлагаю же все в один запихать. Чем больше, тем лучше, но работать должен каждый, чтобы сделать deployment continious.
            Собственно, это все, наверное, философия, но факт в том, что я долго ковырялся в интернетах и так и не нашел, как запускать тесты на всех коммитах пуллреквеста. Вопрос-то про это был.


            1. eyeofhell
              04.11.2015 17:15

              Видимо это от того, что большинство разработчиков придерживается того же подхода что и я: коммиты — штука промежуточная, результат работы — это пуш. Проверять надо только результат работы.

              Чем помочь вам не знаю :(. На вскидку — форкнуть gitlab и сделать нужное поведение в коде. Но это вызывает множество вопросов с отображением, останавливаться ли если очередной коммит не прошел тесты, делать ли деплой на последнем или на всех… Вообщем странная и сложная штука. Если так нужно — дерзайте!


              1. Monnoroch
                04.11.2015 17:16

                Я тоже пока вынужденно вашего метода придерживаюсь, но это только от безысходности :(


                1. nmike
                  04.11.2015 21:06

                  ну так настройте пушь после каждого коммита — будет вам счастье.


                  1. Monnoroch
                    05.11.2015 01:14

                    Что это значит? Я же не в мастер коммичу, я делаю бранч, в нем работаю, а потом делаю пуллреквест. И хочется запрещать мерж пуллреквеста, если в нем есть плохой коммит.


                    1. nmike
                      05.11.2015 02:58

                      Вы работает в бранче. После комита в бранче, настройте автоматический пушь бранча. Так получите проверку каждого коммита. Только вот если у вас с коммитом плохо, все превращается, как вы сказали:

                      методологию разработки «сделай как-нибудь, а потом допили до зеленой кнопочки».


                      Вообще, вам не это вероятно надо, а настроить хуки на прогон тестов на локальной машине на каждый коммит и реджектить его, пока не станет «зеленым».

                      Просто не понятно, вот вы сделали 10 комитов в ветку и пушите. И на сервере есть проверка каждого коммита. И вот у вас 7 завалилось — чем это лучше? и что вы будут делать на сервере с уже запушинными «красными» комитами?


            1. asm0dey
              04.11.2015 22:28

              Зависит от того, придерживаетесь ли вы идеи с фичебранчами. Мне они нравятся как раз тем, что там можно творить любой ад и это не портит главную ветку репозитория. Бывают гигантские задачи с огромными по объёму рефакторингами. Закоммитить их в рабочем состоянии посередине может быть нереально.


              1. Monnoroch
                05.11.2015 01:12

                При чем тут фичебранчи? Какой бы ветка ни была, при мерже её в мастер либо сквошить и терять историю, либо не сквошить и портить мастер плохими коммитами, либо пускать тесты как-то не через систему.


                1. asm0dey
                  05.11.2015 07:59

                  Я не совсем понимаю почему мастер будет испорчен плохими коммитами. Мы ж не ребэйзим, мы мёрджим, так? В мастере будет один коммит про то, что смёрджен бранч такой-то, какие бы коммиты в этом бранче не были.


          1. mird
            04.11.2015 23:32

            А так откатили коммит и получили не рабочую версию. Непорядок.