Использование TeamCity внутри компании JetBrains. Евгений Кошкин (2016г)

Этот доклад 2016 года, но он все равно полезен для тех кто хочет разобраться как работает TeamCity.



Здравствуйте, очень рад здесь сегодня быть и видеть такой живой интерес к нашему продукту. Я действительно разработчик TeamCity. Я работаю над продуктом более 7 лет. Моя зона ответственности — это поддержка dotnet технологий в TeamCity. Я руковожу dotnet разработкой. Но в том числе я достаточно много общаюсь с пользователями. И делаю всякого вида доклады на конференциях, в том числе тренинги мы делаем для пользователей и помогаем использовать наш продукт правильно, эффективно и т. д.

Сегодня я хочу поделиться опытом использования TeamCity внутри JetBrains и теми подходами, которые мы используем. Я, надеюсь, что вам будет полезно.

У нас обязательно будет сессия вопросов и ответов в конце, поэтому, если вдруг что-то я не освещу, то у вас будет возможность спросить.

Я начну немного издалека. Расскажу про настоящее компании и продукта.

t4lfnblfb5aacjpcrft-kewixvw.png

JetBrains сегодня — это офисы в 4-х странах, в том числе у нас есть небольшой офис в Москве, где, кстати, сидят несколько разработчиков TeamCity тоже.

У нас 20 продуктов. Из них 16 персональных и 4 продукта для команды. Это те продукты, которые мы уже анонсировали. Кое-что вариться из того, что мы еще не анонсировали, но через какое-то время тоже будет доступно.

Компания достаточно быстро растет. Количество разработчиков превышает 500 человек, потому что у нас в компании в основном разработчики. У нас минимальное количество людей, которые не занимаются разработкой. Даже те, кто у нас числится менеджером, это тоже обычно разработчик. Даже девчонки на ресепшене сидят и что-то на Javascript делают.

Соответственно, компания очень быстро сейчас растет, особенно в последние 5 лет. И количество сотрудников в разы увеличилось. Очень много продуктов было выпущено.

И активных пользователей только наших персональных продуктов, по-моему, больше 3 000 000 человек в мире, т. е. именно разработчиков. Это достаточно хороший результат, мне кажется. И это число растет постоянно.

verieqox9zgal8qe8g60itqnd7m.png

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

И еще выпускаем на каждый из этих апдейтов по минимум 5 bugfix апдейтов. И каждый месяц мы что-то релизим. Это либо bugfix апдейт, либо какой-то фич апдейт.

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

wjy3b9hjpqpagaoncis5fkfenfo.png

У нас есть внутренняя инсталляция в TeamCity, которая собирает все продукты JetBrains. Вообще, это особенная инсталляция, потому что из нее продукт и вырос.

Все продукты JetBrains появляются и развиваются примерно по одному и тому же сценарию. Мои коллеги, когда разрабатывали эту идею, они столкнулись с тем, что на тот момент ни один инструмент, ни одна build система не удовлетворяла требованиям, которые возникают при разработке сложного java приложения. И было решено сделать свой build сервер. Вот так в JetBrains и появился TeamCity.

Все это время продукт эволюционировал. И во многом эволюционировал как ответ на новые требования нашей увеличивающейся компании. Когда продуктов стало очень много, команд стало очень много, мы сделали иерархию проектов. Когда коллеги стали перелезать активно на использование Git, мы сделали поддержку фич бранчей Git. Т. е. очень многие фичи — это реакция на потребность наших коллег, которые делают сложные продукты для dotnet, java и т. д., поэтому поддержка в TeamCity получается достаточно хорошая.

Вот примерные цифры размера нашей инсталляции. Это я взял нашу статистику:


  • У нас более 500 активных проектов.
  • В нем около 4 000 активных конфигураций.
  • У нас больше 300 build агентов подсоединено к этой одной инсталляции.
  • Builds наши в среднем достаточно массивные. Максимальное количество текстов, которое исполняется в одном build — это 53 269.
  • В среднем по компании build длится 25 минут. И поток builds достаточно большой, потому что в день происходит около 3 000 коммитов во всей компании. И, соответственно, build-сервис все эти коммиты обрабатывает, запускает builds.
  • В среднем 6 000 задач каждый день стартуется.

Т. е. нагрузка на этот внутренний build-сервис достаточно большая. И так или иначе все, что я буду сегодня рассказывать, будет касаться этой инсталляции.

3j04u02wy79rkol14qy17cvzplc.png

Что конкретно я бы хотел осветить сегодня?


  • Во-первых, познакомлю со своим взглядом на базовые понятие TeamCity такие, как конфигурация, проект, шаблон, зависимость, build agents и т. д. Расскажу некоторые детали и особенности использования внутри всех этих понятий.
  • Дальше отдельно остановлюсь на очень важной фиче. Это снапшот зависимости. Я расскажу о том, какие есть варианты применения этой фичи. Как показывает практика, пользователи не совсем понимают, зачем это нужно и как правильно использовать эту фичу. Она является краеугольным камнем в TeamCity. И аналогов на рынке нет. И я уделю отдельное время этой фиче.
  • Я расскажу о подходах к управлению окружением на build agents, которые мы сейчас используем. Build agents много, их 300 штук. Там разные environment для того, чтобы исполнять тесты наших продуктов. И нужно как-то всем управлять.
  • Потом расскажу о том, как TeamCity скелится внутри компании, т. е. в частности в 10-ой версии мы выкатили новую фичу, которая позволяет доставлять еще дополнительный TeamCity сервер, который часть нагрузки с основного сервера на себя снимает.
  • Потом коснусь практик администрирования TeamCity.
  • И потом расскажу про расширение TeamCity, т. е. про всякие плагины, которые в поставку не входят, но мы внутри компании их используем, и они достаточно полезны нам.

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

Последние четыре пункта будут в том числе полезны проектным администраторам и людям, которые так или иначе вовлечены в администрирование TeamCity.

mg0lsart4otvesvuiggncqcylmk.png

TeamCity реализует концепцию competition green, т. е. есть основная нода, которая распределяет задачу по вычислению чего-то на второстепенные ноды. Второстепенные ноды — это build agents. Основная нода содержит все данные про конфигурирование этих задач и реагирует на события внешней среды. Т. е. на коммиты version control, на появление артефактов в control репозитории и т. д. И запускает задачу.

Ноды, которые называются, build agents, они репортят на сервер этой задачи и все результаты их исполнения. Соответственно, сервер в том числе поддерживает очередь задач, т. е. если подходящих для исполнения конкретных задач агентов нет, она ставится в очередь и живет там, пока этот агент не появится. Очередь переживает restart, т. е. вы можете выключить сервер и включить обратно, но состояние очереди сохранится.

И в том числе важной особенностью является то, что если в какой-то момент сервер ушел, например, вы производите апгрейд, то агенты переходят в режим накопления данных, которые потом они отправляют на сервер, когда сервер снова поднимется. Таким образом вы можете при апгрейде сервера не потерять ни байта данных, которые должны были пересланы из builds на сервер. А после того, как агенты свои существующие задачи после апгрейда сервера закончат, они получат команду на апгрейд и сами уйдут на апгрейд.

ykaagjqehrve8zws-npypoteuvc.png

Build Agent — это java-процесс, который запущен как консольное приложение, либо как сервис на какой-то машине. Он умеет принимать задачи по построению, тестированию, деплою и какие угодно задачи от сервера. Умеет репортить обратно ход их исполнения и какие-то артефакты, которые в процессе были сгенерированы и т. д.

Все множество агентов, авторизованных на сервере, делятся по пулам. Пулы очень полезно использовать для того, чтобы доступные ресурсы как-то распределять между командами разработчиков. Т. е. у нас внутри для разных команд есть выделенные свои пулы. И это гарантирует, что если мы в TeamCity запускаем много builds, то это не выест все ресурсы сервера, а выест только в нашем пуле. И время ожидания builds в нашей очереди будет больше, но это никак не зааффектит команду …, либо dotnet команду.

v7ugxfchb7_3fjwdfdqynstjsj4.png

Кроме того, что агент умеет репортить на сервер информацию о задачах, которые он исполняет, агент также рассказывает серверу об окружении, в котором он ранится. Т. е. о том, какие tools стоят в этот момент в операционной системе. Он репортит это через свои конфигурационные параметры. Там поддерживается плагины, т. е. там вы можете написать плагин, который будет репортить с агента какие-то специфичные и нужные для вас tools, если из коробки это все не доступно.

Эти знания про environment на built agents нужны серверу для того, чтобы запускать задачи только на тех нодах, которые совместимо могут выполнить успешно эту задачу.

7nhp1l6mnbvdvyr8b1ovtvmtnbw.png

Build configuration — это основная единица конфигурирования TeamCity. По сути, содержит все множество настроек, описывающих ту или иную задачу по сборке. Это, например, список репозиторий, откуда нужно брать исходный код, либо builds скрипты, последовательность шагов, необходимую для сборки критерий запуска задачи, критерий успешности выполнения задачи и требования, например, к агентам, которые эти задачи предоставляют.

alhlhjnda2wnvjdqdnebqhf0fa0.png

Build configuration объединяется в проекты. Проекты, кроме того, что являются контейнерами для build configuration, они являются контейнерами для других проектов, т. е. проекты могут быть вложенными, они образуют иерархию.

Соответственно, на проектном уровне вы также можете определить некие свойства, которые будут общими для всей конфигурации из этого проекта. Например, включить или выключить сохранение настроек version control, определить SSH ключи, необходимые для работы этих конфигураций, чтобы конфигурации не внутри себя определили эти ключи, а просто использовали их.

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

Еще одно применение проектов — это разграничение прав доступа к тем или иным конфигурациям. К примеру, какие-то конфигурации, связанные с deployment вашего сервиса или приложения в production, можно вынести все эти конфигурации в отдельный проект, дать права на использование и на запуск builds в этом проекте, и на изменение настроек этого проекта только отдельным пользователям. Соответственно, вы сможете ограничить тем самым круг людей, которые могут делать deployment.

Вот этот тренд по перенесению всего в TeamCity на уровень проекта, это глобальный тренд. Он много версий продолжается. И будет продолжаться дальше.

Наша основная задача — сделать так, чтобы при появлении новой команды внутри компании, мы, люди, которые администрируют TeamCity сервер, создали им root«овый проект, назначили кого-то из их команды project admin«ом и потом полностью делегировали ему все дальнейшие задачи по конфигурированию TeamCity. Т. е. мы хотим наши фичи писать так, чтобы при использовании их на уровне проекта, не нужно было делать никаких глобальных админских настроек.

И в частности до 10-ой версии нельзя было, например, авторизовать агентов в свой пул. Даже если у вас был свой собственный пул для своего проекта, у проектного админа не было для этого прав. Нужно было идти к системному админу и просить его авторизовать агенты. В 10-ой версии мы сделали так, что если у вас есть админские права на все проекты, ассоциированные с пулом, то вы сможете сами авторизовать агенты.

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

Т. е. это такой глобальный тренд, мы постепенно все наши фичи переписываем на такой лад. И это, кстати, один из примеров использования TeamCity внутри JetBrains, потому что, как я уже сказал, этот внутренний instance TeamCity наша команда TeamCity сама администрирует. И поэтому нам отвечать и делать все настройки для всех людей в компании, коих уже больше 500 человек, не хочется. Поэтому мы стараемся делать так, чтобы мы могли делегировать всю эту работу. При этом сделав так, чтобы их настройки никак не аффектили людей из других команд.

yju5shmce1c6gzvj0mrryphnd5m.png

Следующая сущность — это зависимости между конфигурациями. Конфигурации могут быть связаны с зависимостями.

Простейший вид зависимости — это артефакт зависимость.

Простейший пример приведу. Если у вас есть приложение, вы используете API какой-то библиотеки в runtime, то, соответственно, чтобы разрешить такую зависимость во время build, вы можете в TeamCity использовать артефакт зависимость между двумя конфигурациями. При этом вы можете использовать последний собранный build библиотеки, т. е. последний успешно собранный, либо какой-то протеганный build. Либо, если вы используете артефакт, то вы можете публиковать артефакты библиотеки в сторонний репозиторий. И потом оттуда его резолвить во время bulid«а приложения.

Второй путь имеет некоторые плюсы. И частности, если вы используете сторонний репозиторий артефактов и не используете напрямую зависимости TeamCity, вы не теряете локальную воспроизводимость builds, что является очень важным свойством. Потому что, если у вас разрешение этой зависимости отражено только в TeamCity в виде зависимости между конфигурациями, локально собрать правильно build вашего приложения на правильную ревизую у вас не получится. Потому что вам нужно будет пойти в TeamCity и понять, какая версия библиотеки в том build использовалась и, соответственно, сделать много ручных действий.

Локальная воспроизводимость builds — это очень важное свойство, которое нужно стараться до последнего не терять. Отказываться от этого, только если есть резкие причины.

Артефакт зависимости вы наверняка используете так или иначе.

qbc_hj0oilhlufzferk5c3qppzo.png

Кроме этого есть такая сущность, как шаблон конфигурации. Кроме механизма наследования каких-то свойств через проекты в TeamCity реализован еще один механизм наследования. Это build configuration template.

Стандартным примером является тестирование какого-то приложения на нескольких платформах. В простейшем случае у вас есть конфигурация, которая гоняет тесты. У вас есть какая-то артефакт зависимость на конфигурации, которые собирают артефакты, которые вы тестируете. И есть много build agents с разными машинами. Есть, например, VCS Trigger, который у вас подмонтирован к этой конфигурации. И вы запускаете эти тесты на всех этих машинах. Это рабочий вариант, но идея не очень хорошая.

Почему? Потому что у вас есть тесты, вы таргите несколько платформ, у вас есть одна конфигурация и много build agents, на которых вы запускаетесь.

Общая проблема в том, что у вас в истории builds этой конфигурации будет смешанный статус на разных платформах. Он будет у вас мигать. Т. е. если у вас тесты падают только на Linux, то у вас время от времени build будет то зеленым, то красным. И это плохо. Так делать не стоит. Стоит разделять тесты на разных платформах на разные конфигурации. И чтобы переиспользовать настройки между ними, надо выделять шаблон.

7oaizcdxkwvw0fwud070upjlmei.png

Шаблон, по сути, это тоже конфигурация. Но чем отличается шаблон от конфигурации? Некоторые свойства в нем параметризованы. Т. е. в качестве значений этого свойства используется ссылка на какой-то параметр. Соответственно, создавая новую конфигурацию на базе какого-то шаблона, в дальнейшем, когда у вас появится новая таргет-платформа, вам нужно будет только указать пару параметров и у вас будет новая рабочая конфигурация. А все остальные настройки будут переиспользованы.

wbv_irxzvddyd56c6suyqrroz4i.png

И мы дошли до важной сущности — снапшот зависимости. Идея снапшот зависимости достаточно простая. Когда вы говорите, что у вас одна конфигурация зависит по снапшоту от другой конфигурации, то вы говорите, что builds этих двух конфигураций должны собираться консистентно, т. е. относительно одной и той же ревизии, либо снапшота в version control, либо в нескольких репозиториях. Потому что поддерживается даже тот случай, если у вас исходники лежат в одном version control или в одном репозитории, а другие исходники в другом. Т. е. работает даже такой снапшот между разными репозиториями.

Такой тип зависимости дает очень много плюшек. И не все они очевидны.


  • Во-первых, с помощью наведения таких зависимостей между конфигурациями вы можете получать в некоторых случаях, в которых раньше не могли, консистентные builds. Т. е. если у вас какое-то приложение или сервис имеют много компонентов, то частенько бывает проблемой сделать какой-то build всей системы, чтобы все его компоненты были консистентные, т. е. собрались относительно какого-то конкретного момента времени и снапшота.
  • Использование этой фичи позволяет вам триггерить ваши builds эффективно.
  • Кроме этого, версионировать ваши компоненты удобно.
  • рименяется при построении build pipeline, т. е. если у вас есть какой-то continuous delivery pipeline, то в TeamCity это все конфигурируется с помощью снапшот зависимости.
  • А также это очень помогает, когда вы делаете релизы, потому что есть такая фича, как исторический build, я тоже об этом расскажу.

Теперь давайте разберем по порядку.

Самый простой случай — это консистентность builds.

cikeyddjhxnqdjprpwisjcwbj8c.png

Рассмотрим пример. У нас есть какое-то приложение. Оно кроссплатформенное. Оно содержит какой-то Windows специфичный код, Linux специфичный код и есть какая-то библиотека, которая ранится вне зависимости от платформы.

В runtime Linux и Windows специфичные части используют API этой библиотеки. И приложение содержит в себе все эти компоненты: библиотеку и платформо-зависимые части.

Особенностью такого приложения может являться то, что в рамках одной машины вы такое приложение собрать не можете. Т. е. вы обязательно должны использовать два build agents с Windows и с Linux. И некоторые части системы будут собираться на Windows, некоторые на Linux. В этом случае, когда вы не можете все собрать в рамках одной последовательности шагов, в рамках одного build на одной машине, то у вас здесь могут быть проблемы с консистентностью builds.

nptaybm_4sivp5qtagybymrwoc0.png

Как будет выглядеть простейшая конфигурация? У меня есть build конфигурация, которая компилирует sorts библиотеки и публикует ее как артефакты. Вот эти стрелочки — это артефакт зависимости. У меня есть платформо-зависимые части, которые используют собранные эти артефакты. Они не компилируют код библиотеки сами, они используют это как артефакт. И есть build приложения, который все собирает вместе, строит какой-то пакет и т. д.

Предположим, вы сконфигурировали в TeamCity вот такую схему, т. е. используете только артефакт зависимости. У вас разработчики делают какие-то коммиты, т. е. у вас есть какой-то поток коммитов, соответственно, у вас есть какой-то набор build agents, из которых некоторые совместимы с этими задачами, некоторые с этими и т. д. И может сложится так, что последовательность всех этих builds будет перемешана. Когда вы используете артефакт зависимости, у вас есть последний собранный build, последний успешно собранный build и протеганный build.

gz8-no7z2dazod1rfxk6apqzneg.png

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

lxvjp8zq6dms9lfp5dsgjppzvxw.png

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

После этого TeamCity вам гарантирует, что builds во всех этих конфигурациях, т. к. они связаны снапшот зависимостями, будут образовывать цепочку builds — build chain. Это такое понятие в TeamCity. И в рамках конкретного build chain вы будете гарантированно иметь консистентное состояние.

Проблема заключается в том, что если вы публикуете свои артефакты и резолвите их из стороннего репозитория, то для вас эта картинка не работает. Потому что TeamCity одновременно знает и про снапшоты, и про артефакт зависимости. И когда он резолвит конкретную версию артефакта, он обращает внимание на снапшот и берет именно правильный артефакт. Если все это публикуете в artifactory, то вы все равно берете либо снапшот, либо какую-то конкретную версию.

Это тот случай, когда выгодно использовать артефакт зависимости внутри TeamCity и не публиковать в сторонний репозиторий артефактов, либо, может быть, дублировать эту публикацию.

На самом деле снапшот зависимость, артефакт зависимость, она не добавляет никакой семантики. TeamCity все равно, что вы там собираете, например, сборка чего-то, выкладка чего-то и т. д. Если вам важно деплоить консистентно несколько компонентов системы, то все тоже самое. Представьте, что у вас здесь не сборка артефактов, а выкладка какого-то набора микро-сервисов на staging или на production. Тогда у вас есть root«овая конфигурация, которая называется deploy все. И она будет зависеть по снапшотам от всех остальных конфигураций. И с помощью этого root«овой ноды вы будете иметь возможность делать все консистентно, все за один раз. И если выкладка одного из компонентов сломалась, то вы сможете ее передеплоить именно снова в консистентное состояние, а не последнее собранное.

m3ws5su7pqgxec6akld0kt17ioa.png

Следующий аспект — это как снапшот зависимости позволяет триггерить ваши builds эффективно.

mq_t-lhxmxcx9mkzupjqjo2r_i8.png

Обычно подход здесь такой. Сначала у меня должна собраться библиотека. Когда она собрана, должен собраться, например, вот этот компонент. Когда он собран, должно собраться само приложение. И обычно это устанавливается как trigger after. Т. е. триггерится, когда build другой конфигурации завершен.

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

gb_a0rslnn1r8w53ktk8n7dnhgw.png

И TeamCity предлагает альтернативный подход к триггерингу. Вы вообще не должны думать о том, как зависимость будет исполняться, вы должны думать о результате, т. е. что вы хотите получить. Вы хотите получить build вашего приложения. Там есть какие-то изменения в этом графе. Graf может быть огромным, TeamCity собирается ровно также. У него огромное количество плагинов и огромные графы слева.

Но мы хотим собрать просто build TeamCity. И все что мы делаем, это вешаем только один триггер на root«овую конфигурацию и выставляем там магическую галочку «триггерить build на изменение в снапшот зависимости», которая по умолчанию выключена. И вы вообще дальше ни о чем не думаете. TeamCity за вас определяет в каждый конкретный момент времени builds, какие компоненты должны быть собраны и builds, какие компоненты должны быть пересобраны, потому что одна из зависимостей, например, изменилась.

8ncy1z2tvzvbrui8o4uvlypxtq4.png

Если в какой-то момент у меня изменился Windows специфичный код, у меня есть триггер только вот здесь, но TeamCity поймет, что весь build chain хочется запускать при таком изменении, значит, этот build будет пересобран. У вас появится новый артефакт этой версии, остальные части системы этими изменениями не были зааффекчены и пересобраны не будут. Так как у вас изменилось один из компонентов приложений, build самого приложения тоже будет пересобран. При этом эти артефакты будут переиспользованы, вы сохраните себе время на build agents, т. е. эти builds вообще запущены не будут.

aa8ua_-ceyakn7roqejz0wrby5a.png

И наличие этой фичи позволяет нам экономить огромное количество build time у нас внутри.

Это старенький скриншот. Когда build time, который занимал всех агентов на сервере, был 3 558 часов. И каждый день мы на тот момент 870 + 509 часов экономили за счет наличия снапшот зависимости и переиспользования артефактов внутри builds.

994ugrhfrrf6enloudev0rzsgte.png

Это приводит к тому, что вам нужно покупать меньше build agents, потому что меньшее количество build agents ваши нужны обслуживает, потому что builds переиспользуются.

Почему мы эту фичу не сделали приватной? Потому что мы так не делаем. Все, что мы делаем, мы делаем для себя и для пользователей в том числе.

Manage application components version

Следующая фича, которая доступна с помощью снапшот зависимости — это управление версиями приложения, версиями компонент или микросервисов внутри большого сервиса.

4w4chkpynmp6lfj3jvkix53ned4.png

Важным свойством снапшот зависимости и цепочки builds является то, что не только артефакты, которые доступны в рамках этого build chain, составляют общий контекст, но и параметры всех builds составляют общий контекст build chain.

И в рамках этого контекста у вас есть возможность из build одной конфигурации получать доступ к значениям параметров другой конфигурации.

Например, если у вас есть конфигурация A, в котором есть какой-то параметр, у которого значение foo в рамках конкретного build. Если build из конфигурации B в одном chain, т. е. консистентный с этим build, то вы можете в качестве значения параметра B использовать значение, например, вот этого параметра.

bg3vm2i_fvfatbmjkozmqox3ffw.png

Что это вам дает? Обычно, когда вы говорите о версионировании каких-то компонентов, либо сервисов, то у вас всегда есть какой-то шаблон, в соответствие с которым версия присваивается. И у вас есть какая-то статическая часть, которая обычно захардкожена на уровне build конфигурации. И есть какая-то динамическая часть, которая меняется от build к build. Вот этот синтаксис — процент что-то процент — это ссылка назначения какого-то параметра в TeamCity.

Соответственно, первое, что приходит на ум, если у меня много компонентная система и всем этим компонентам нужно присваивать какую-то версию, это на уровне конфигурации захардкодить такой шаблон. Но тогда у меня будет дублирование. У меня будет 4 места в системе, где у меня этот шаблон будет захардкожен.

Я могу, конечно, наследовать все от какого-то шаблона. Этот шаблон определить на уровне проекта и тоже переиспользовать. Но будет проблема, что если у меня эти builds не исполняются консистентно, т. е. если нет снапшот зависимости, то эта динамическая часть будет не обязательно одинаковой. И получается, что в пакет вашего приложения, возможно, будут попадать компоненты, которые будут иметь разный build number. Потому что build number — это локальный счетчик в рамках каждой конфигурации. И он разный в каждой конфигурации. Если здесь 10 builds прошли, а здесь 11, то здесь будет 11 build number, а здесь 10. И общей версии для всех компонентов не будет.

ny94gxgsnj8vex_asjmwgjfbyow.png

Как сделать правильно? Я уже сказал, что в рамках build chain у нас есть общий контекст параметров и мы можем ссылаться из параметра одного build на параметр build из другой конфигурации. Мы это можем делать с помощью вот такого синтаксиса.

Расшифровываю. Здесь сказано dependency с такой-то ID и имя property, которую я хочу использовать. Такую подстановку я могу использовать в качестве значения своего параметра. Таким образом, я могу в самой первой исполняемой конфигурации определить параметр version, который будет, например, 1.0.build number, т. е. build number в рамках этой конфигурации. Во всех остальных конфигурациях в качестве версии я буду использовать ссылку на параметр из build из этой конфигурации. Таким образом шаблон у нас определен единственным образом, и мы гарантированно получаем во всех зависимых builds одно и тоже значение версии.

И это все работает не только в read only режиме, т. е. мы не только ссылаться можем на значение параметра и зависимости, мы можем и форсировано выставлять им какие-то значения. Т. е. работает синтаксис revers всем обратным зависимостям, ID которых удовлетворяют какому-то параметру. Т. е. это либо явно указанный ID, либо звездочка. И можем выставить параметр с таким-то именем в какое-то конкретное значение.

Это может быть полезно, когда у вас есть в скриптах, которые собирают каждый из компонентов, например, какой-то параметр. Например, isRelease, который во время компиляции транслируется в код. И таким образом вы потом включаете и выключаете exception, либо еще там что-то делаете. И вы пробрасываете это не через config, а прямо в код это делаете. И, соответственно, у вас зависимостей может быть много и дефолтные значения isRelease в каждой из зависимости могут быть разные.

Но в какой-то момент вы хотите собрать build, чтобы гарантировано все компоненты получили правильное значение этого флажка. И вы стартуете свой build в этой конфигурации, в нашем случае — это build приложения, и говорите «всем зависимостям выставить isRelease true». И вы гарантированно получите правильное значение этого флажка во всех зависимостях. Переиспользованы такие builds не будут, потому что прошлые builds были собраны с другими значениями. У вас будут гарантировано пересобраны все ваши зависимости, но с другой стороны вы получите то, что вы хотите.

9iga61ureavzfuggw9jcunne-l8.png

Следующий аспект — это немножко про continues delivery.

dftcm2-va-0ylicctnvczqbcpnq.png

Представьте, что у вас есть какая-то конфигурация, которая собирает дистрибутив вашего приложения, либо это пакет, который вы в дальнейшем выкладываете на staging, production.

У вас есть какие-то acceptance tests. У вас есть процедура deploy on staging. Она оформлена как build конфигурация. И есть deploy to production.

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

Соответственно, как здесь снапшот зависимость помогает? К примеру, я хочу, чтобы на каждый коммит version control мое приложение собиралось, прогонялись acceptance tests и выкладывалось на staging, но при этом, чтобы в production выкладывалось только то, что я сказал явно руками. Как это можно при помощи снапшот зависимости реализовать?

nd51l7jprkrtcbbq7myi8ka2of4.png

Во-первых, как показано на схеме, я объединяю мои конфигурации снапшот зависимостями, т. е. говорю, что deploy production зависит от build dist. Deploy on staging зависит от acceptance tests. А тесты зависят от build dist, потому что именно этот артефакт они будут в дальнейшем тестировать.

xff1ie6cbqu3zjpagsk4t8pykwq.png

Дальше я добавляю VCS Trigger сюда, т. е. я хочу выкладывать на staging при любом коммите. Сюда я никакой триггер не добавляю, потому что я хочу ручное управление.

37safzna-etyailwlzk7ht7_55q.png

Как реализовать это ручное управление? Есть такая фича, которая называется build promotion. Promote — это действия пользователя, которые доступны для конкретного build в этой конфигурации, если есть входящие снапшот зависимости в эту конфигурацию, которые позволяют мне конкретный build дальше протолкнуть по моему pipeline в том направлении, в котором я хочу.

y5fxph8s1dqcnh7nnmqxeaianya.png

Вот реализована моя схема. Я залогинен под пользователем ekoshkin, который является девелопером. П

© Habrahabr.ru