Неделя GitLab CI на Хабре! В 2015 году мы уже писали о встроенной в GitLab системе Continuous Integration. GitLab часто ругают за предательство идеалов UNIX way и интеграцию слишком большого количества функций в одно приложение. Зато насколько удобно пользоваться этими функциями! За те полтора года, что прошли с момента нашей публикации, ребята сделали «Environments», добавили возможность сделать кнопку «раскатать на прод» и множество других улучшений. Под катом я расскажу о накопленном опыте, как небольшим командам автоматически собирать и выкладывать на прод/стейдж не только скрипты Voximplant для телефонии, но и другие проекты — сайты и сервисы.

Ветки или окружения?


Когда мы делаем автоматическую сборку и выкладку наших проектов, то на входе получаем вопрос: как определять, что и куда выкладывать? Есть несколько подходов. И в прошлой статье я описал самый простой: система CI собирает и выкладывает в зависимости от ветки. Пушим в «master» (или в «dev», если у нас «master stable»), и наша сборка выкладывается на стейджинг. Мерджим в «prod» (или в «master», если у нас «master stable»), и сборка выкладывается на прод. У подхода есть плюсы и минусы. Лично мне в таком подходе не очень нравится двойное назначение веток, для многих микросервисов за глаза хватает одного «master», а «prod» превращается в кнопку «выложить на прод». Плюс, тестирование веток превращается в интересную историю.

Второй вариант, который авторы GitLab предложили в версии 8.9, это отдельная абстракция для «как собирать и куда выкладывать». Абстракция называется «environments» и позволяет раскатывать сборку по нажатию кнопки в пользовательском интерфейсе GitLab. Выглядит это следующим образом: в YAML-файле конфигурации Continuous Integration мы задаем произвольное имя Environment и пишем код для сборки и выкладки:




Все, что делает абстракция, это добавляет кнопку «раскатать сюда» в интерфейс GitLab. Очень удобно на стейджинг раскатывать автоматически, а на прод — по нажатию на кнопку. На стейджинг из «master» можно раскатывать автоматически (отсутствует when: manual и указано only: master), а в остальные окружения и из веток — по нажатия на кнопку:


Боремся с копипастой


Сценарий Continuous Integration пишется на YAML. Это такой Python-образный JSON с несколькими бонусами. Один из таких бонусов, поддержка которого появилась в последних версиях, это anchors – чтобы пометить часть конфига идентификатором, а затем повторно использовать его в другом месте. Это позволяет написать обобщенный скрипт сборки и раскатывания, а затем «скопипастить» его для разных окружений, модифицируя только переменные окружения. Например, на платформе Voximplant NDFLka.ru собрали сервис, автоматически распределяющий входящие звонки по сложной бизнес-логике. Для такого сервиса можно сделать dev и prod приложения с разными номерами телефонов (для dev можно использовать номер телефона в «Готем Сити», аренда которого стоит один цент в месяц), а затем раскатывать dev автоматически, а prod — уже вручную, ответственным человеком, по результатам тестирования:


Используем Docker для сборки


Как и все современные CI, GitLab просит вас запустить «runner» на каком-нибудь компьютере, и скрипты, которые вы прописываете в «script», запускаются на этой машине. Если у вас много разных проектов, то для их сборки и деплоя могут понадобится разные, зачастую несовместимые с собой версии тулчейнов. GitLab предлагает решение этого вопроса, бесшовно интегрируясь с docker. Достаточно задать образ нужного контейнера в поле «image», и GitLab выполнит команды «script» в указанном контейнере. Более того, для разных шагов сборки можно использовать разные контейнеры, передавая между ними результаты сборки как «artifact». На практике удобно написать собственный Docker-контейнер для сборки проекта, держать его в том же Git-репозитории, что и сам проект, и указывать через git url:


Чего стоит ожидать?


Gitlab очень быстро развивается. В течении последних нескольких месяцев мы получили отображение CI в реальном времени, первые тестовые имплементации автоматического деплоя в kubernetes и множество других небольших улучшений. Огромный комбайн – это не всегда хорошо. Но в случае с GitLab я в ребят верю, если они будут продолжать развитие продукта, то мы можем получить лучшее CI-решение, бесшовно интегрированное с управлением исходниками и системой работы с задачами. Ваше мнение?
Поделиться с друзьями
-->

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


  1. andr1983
    11.07.2017 13:52
    +6

    Ветки обычно используется не для выкатки кода при Continuous Integration а для разделения стабильной части когда (например master) и кода в разработке (development). Мне кажется вы путаете понятия.


    1. r-moiseev
      11.07.2017 22:08
      +2

      Если у вас фичер бранчи, ветка develop вам не нужна

      Согласно GitHub Flow в мастер попадают фичи готовые к продакшну, релизы вы делаете тегами.

      Однако GitLab таки рекомендует использовать бранчи для енвов Объясняется это тем, что вы не всегда контролируете процесс резила, например в случае с мобильным приложением.


      1. VolCh
        16.07.2017 00:56

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


  1. xtraroman
    11.07.2017 15:56
    -1

    У меня отрицательный опыт работы с этой системой
    Почему кто то решил что включение Pipelines по умолчанию сделает мир лучше?

    1. В одном проекте надо было настроить чтобы Gitlab Только хранил сорцы, CI уже был настроен на appveyor. Так и не вышло нормально настроить эту связку. На один коммит appveyor билдит несколько раз.
    2. Если в проект добавить YAML файл а потом удалить, таски из него навсегда останутся в Jobs
    3. Саппорт гитлаба не очень.
    4. Доки не очень. Часто попадаются решения для админов gtlab server которые неприменимы когда gitlab используется как сервис.


    1. Envek
      11.07.2017 23:35

      2 — это не баг, но фича. На каждый коммит (точнее даже на пуш ветки или тэга) GitLab создаст Pipeline с ровно такой конфигурацией, какая задана в .gitlab-ci.yml для этого коммита (и для той ветки/тэга, в которой он был). Это позволяет тестировать разные варианты конфига CI в отдельной ветке и вообще экспериментировать. И то, что билды остаются в истории — это хорошо. Потому что как только вы начинаете деплоить с помощью GitLab CI, то вывод консоли утилиты деплоя теперь видит не только тот, кто деплоит, но вообще все и в случае любых проблем с деплоем ссылка на job'у скидывается в чат и сразу несколько пар глаз могут посмотреть, в чём проблема.


      На прошлой работе (где был запрет на публичные облака — всё хостили во внутренней сети компании) использовали GitLab CI и не нарадовались. Легко конфигурируется, кастомизируется, собирает и пушит докер образа, гоняет тесты, деплоит тестовую и боевую среды, ветки со специальными именами деплоит на специальные review app'ы, кофе вот только не варит (но при наличии подключенной к сети кофеварки и это можно решить).


  1. PannaCottik
    11.07.2017 22:08

    Один раз получил ТЗ где требовалось настроить CI, где сборка, тестирование и упаковка в докер это была не проблема. Самый проблемный момент это передача контейнера на хаб и деплой проекта. Как осуществляется такая схема я так и не нашел. Так в итоге, как делать полный цикл сборка-тестирование-докер-запуск_контейнера_в_облачном_сервисе? Если есть возможность, прошу поделиться мануалом в личку.


    1. Caravus
      11.07.2017 22:12
      +1

      У гитлаба есть свой репозиторий для готовых образов (на каждый проект!), из которого можно прямо деплоить. Многие облачные провайдеры сейчас так же имеют репозитории — GCE, AWS, Docker Cloud, например. На CI собираем и пушим в такой репо, потом деплоим с указанием ссылок на эти образы.


      1. Roquie
        12.07.2017 11:01

        потом деплоим с указанием ссылок на эти образы.

        Можно подробнее? Сейчас я сделал bluegreen с помощью ansible, закидывая docker-compose на продакшен. Может есть способ проще?


        1. Caravus
          12.07.2017 11:25

          Есть. Я вот например делаю сейчас на базе kubernetes на гугле. Там это решается просто двумя репликами (прода например) которые обновляются роллинг-апдейтом по очереди. То есть я после CI заливаю образы в репо на гугле, и закидываю в kubernetes конфиги по gcloud (гугловая CLI утилитка). Сейчас вот на этой стадии примерно. Размышляю как эти самые конфиги закидывать helm`ом.


          1. Roquie
            12.07.2017 11:45

            Работаю с vds/vps, с облаками дела не имел. K8S пока монструозен для моих задач. На первый взгляд, выглядит это не просто, как вы говорите.


            1. Caravus
              12.07.2017 11:56

              Я не говорил что мой вариант проще :) Я только сказал что варианты есть, стоит поискать. Если ваш проект уже настолько вырос что вам требуется bluegreen — до серьёзных систем оркестрации остался один шаг.
              Из более простых:
              1) Если на vps/vds есть доступ по ssh — можно посмотреть в сторону docker-machine. Отпадает проблема с репозиторием — он сам перекачает с машины собранные образа на машину где их запускать. По разным причинам мне этот вариант не нравится, но попробовать стоит.

              2) Если запрета на использование облаков нет — можно попробовать использовать docker cloud (сервис от самого докера). Он возьмёт вашу машину (или создаст по вашей просьбе) и будет накатывать туда конфиги и образа. У меня например сейчас так поднято, на время переезда.


    1. Envek
      11.07.2017 23:40
      +1

      В GitLab CI можно. Настраиваете работу docker-in-docker (dind) на машине с Runner'ом и запускаете docker build, docker push сколько угодно. Хоть на внешний docker registry, хоть на встроенный в GitLab. Документашка тут: https://docs.gitlab.com/ce/ci/docker/using_docker_build.html


      1. Caravus
        12.07.2017 09:51
        +2

        Я бы не стал рекомендовать dind:

        When using docker-in-docker, each job is in a clean environment without the past history. Concurrent jobs work fine because every build gets it's own instance of Docker engine so they won't conflict with each other. But this also means jobs can be slower because there's no caching of layers.

        И под «jobs can be slower» нужно читать «каждый раз будешь пересобирать образ с нуля». Сейчас пытаюсь настроить всё с «Docker socket binding».


    1. r-moiseev
      12.07.2017 00:14

      Запуск в облаке это уже другая история. Задача CI собрать имейдж и запушить. В случае с хероку, например этого достаточно. Если у вас, например, Swarm, то вы держите в репозитории docker-compose, пушите имейджи, а потом делаете docker deploy.

      Если же у вас голый докер без аркестратора (что странно для продакшна), вы должны этим докером запулить обновленный имейдж и пересоздать контейнер. Сделать это можете с помощью докера удаленно (нужно тащить в CI ключики от апи докера)


    1. VolCh
      16.07.2017 01:01

      на стадии билда docker-compose build; docker-compose push. На стадии деплоя docker-compose up (у нас docker stack deploy, но это нюансы)


  1. lleo_aha
    12.07.2017 02:41
    -1

    Ok guys. Бесшовная интеграция с docker. Docker stages уже поддерживаются?


    1. Envek
      12.07.2017 10:20
      +3

      Какую версию Docker себе на Runner'ы установите, та и будет работать :-)


  1. Phoen
    12.07.2017 12:22

    Хм, а в гитлабе нельзя собирать из тэгов?


    1. Envek
      12.07.2017 19:04

      Можно. Указываете в .gitlab-ci.yml для задачи по сборке чего бы то ни было:


        only:
          - tags


  1. diafour
    12.07.2017 12:40

    Костылик с BUILD_ENV тоже использовали, но начиная с 8.15 появились CI_ENVIRONMENT_NAME и CI_ENVIRONMENT_SLUG.


    Ну и хотел бы уточнить, как у вас происходит сборка сборочного образа? То есть в репозитории есть Dockerfile с описанием образа сборки и Dockerfile с описанием образа приложения. В какой момент и как собирается сборочный образ? Это отдельная задача в пайплайне? Как вы ставите тэг, если вдруг сборочный образ обновился? В общем интересен этот процесс.
    Похоже, что нужно аккуратно ставить тэги или руками запускать сборку сборочного образа или даже менять .gitlab-ci.yml, когда изменится тэг сборочного образа. В силу объёмности нашего проекта, мы используем свою утилиту dapp для сборки и описание в двух Dockerfile не требуется, за обновлениям сборочного образа следит сам dapp. Но теперь в самом docker из коробки есть multi stages и похоже этот способ (с двумя Dockerfile) перестаёт быть актуальным. Что думаете?