Русский
Русский
English
Статистика
Реклама

Ci/cd

Оценочный уровень доверия (ОУД4) и ГОСТ Р ИСОМЭК 15408-3-2013. Введение

18.02.2021 10:20:32 | Автор: admin

Привет, Хабр!


В настоящее время в ИТ индустрии крайне актуальна тема построения процесса безопасной разработки ПО (по англ. Secure SDLC или Secure software development life cycle). Некоторые организации и команды самостоятельно приходят к необходимости такого процесса в своих продуктах, свободно выбирают подходящий фреймворк, инструменты и выстраивают свой вариант безопасной разработки. Другие, подпадающие под внешние регуляции, вынуждены разбираться с конкретными, заранее выбранными регуляторами фреймворками или стандартами. Ко второму варианту относятся многочисленные финансовые организации, деятельность которых регулируется Банком России. В нормативах последнего с мая 2018 года стали фигурировать вопросы анализа уязвимостей и появилась аббревиатура ОУД 4.

Этой статьёй я хочу начать цикл, освещающий процессы безопасной разработки в контексте стандартов серии ГОСТ Р ИСО/МЭК 15408. Моя задача последовательно, фундаментально и лаконично изложить этот фреймворк, чтобы уменьшить порог вхождения в предмет. Материал предназначен для разработчиков, менеджеров, методологов и других людей, которые в силу обстоятельств, вынуждены погружаться в безопасную разработку в контексте ОУД и требований Банка России. В подготовке материала мне помогал независимый эксперт и специалист по информационной безопасности - Рустам Гусейнов.


Подробнее под катом

Оглавление

  1. Введение и цели цикла

  2. История и эволюция фреймворка

  3. Центральный банк как популяризатор ОУД4

  4. Общие положения и концепции ОУД4

  5. Заключение

  6. Полезные ссылки и материалы

  7. Приложение (список сокращений)

Введение и цели цикла

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

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

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

История и эволюция фреймворка

ОУД расшифровывается как оценочный уровень доверия. Из самого названия следует цель фреймворка гарантировать соответствие продукта определенным критериям, заявленным в соответствующих стандартах, чтобы пользователи (заказчики, владельцы, физические лица и т.д.) могли доверять программному или аппаратному обеспечению, прошедшему необходимые проверки и декларирующему через них соответствие необходимым требованиям. Чтобы не уходить в длинную лекцию о разработке, уязвимостях, их эксплуатации и сопутствующих рисках, напомним, что любая ИТ-система теоретически (а на деле чаще всего и практически были бы ресурсы!) несовершенна. Поэтому в силу различных недостатков, связанных с:

- архитектурой (дизайном);

- разработкой (кодированием архитектуры в конечный продукт);

- внедрением (настройкой);

- эксплуатацией (обслуживанием).

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

Рисунок 1. Иллюстрация вектора атаки

Корни фреймворка уходят в становление индустрии ИБ в США в семидесятых и восьмидесятых годах прошлого века. По мере автоматизации и развития системного подхода силовые ведомства стремились гарантировать надежность системных компонентов, используемых государственными структурами для защиты информации. В течение какого-то времени несколько подобных стандартов существовали в различных юрисдикциях параллельно, пока не были объединены международными организациями ISO/IEC в новый, единый фреймворк ISO/IEC 15408 Common Criteria for Information Technology Security Evaluation (или просто Common Criteria то есть Общие Критерии). Любопытные до истории и фактов могут изучить подробности хроники по ссылкам внизу статьи, нас же интересует тот факт, что отечественные стандартизаторы с 2012 года начали анализировать и перерабатывать указанное семейство стандартов, чтобы издать их официально на русском под эгидой Стандартинформа.

Здесь стоит сделать небольшое отступление про статус подобных стандартов. На фоне вступления России в ВТО и либерализации законодательства национальные стандарты перестали быть обязательными на территории Российской Федерации. Сегодня, в соответствии со ст. 27Федерального закона 162-ФЗ О стандартизации, ГОСТы на территории России являются обязательными тогда, когда на них явно ссылаются какие-то нормативно-правовые акты уполномоченных органов государственной власти. Здесь на сцену выходит Центральный Банк России.

Рисунок 2. Титульный лист ГОСТ Р 15408-1-2012

Центральный банк как популяризатор ОУД4

Примерно в то время, когда Стандартинформ публикует первые документы семейства ГОСТ 15408, Банк России, в соответствии с международными трендами, начинает ужесточать требования к информационной безопасности платежей и кредитных организаций. Его целью является обеспечение устойчивости и надежности платежной и банковской системы, в том числе борьба с мошенничеством и несанкционированными переводами. Летом 2012 года принимается знаменитое положение 382-П, которое на следующие 8 лет становится основным нормативом по информационной безопасности для организаций, занимающихся денежными переводами на территории РФ (не считая более нишевых и специфичных требований, вроде стандарта PCI DSS, которые существовали и до этого).

С положения 382-П начинается внедрение ОУД 4 в жизнь финансовых организаций. В мае 2018 года Банк России, сталкиваясь с фактами печальной статистики уязвимостей ДБО и иных публично доступных интерфейсов взаимодействия с клиентами, вносит изменения в упомянутое Положение. Среди них содержится п. 2.5.5.1, цитата:

необходимо обеспечить: использование для осуществления переводов денежных средств прикладного программного обеспечения автоматизированных систем и приложений, сертифицированных в системе сертификации Федеральной службы по техническому и экспортному контролю на соответствие требованиям по безопасности информации, включая требования по анализу уязвимостей и контролю отсутствия недекларированных возможностей, в соответствии с законодательством Российской Федерации или в отношении которых проведен анализ уязвимостей по требованиям к оценочному уровню доверия не ниже чем ОУД 4 в соответствии с требованиями национального стандарта Российской Федерации ГОСТ Р ИСО/МЭК 15408-3-2013 .

В последующие годы это требование, в уточненном и видоизмененном виде, появлялось в других нормативах ЦБ, и по состоянию на 2021 год прямо или косвенно вытекает из:

- 672-П (через ссылку на ГОСТ Р 57580.1-2017, где в требованиях ЖЦ.8 и ЖЦ.20 косвенно формулируется ежегодный ОУД4);

- 683-П;

- 684-П;

- 719-П.

Некоторые шероховатости формулировок и весьма общее указание на границы применимости ОУД в историческом 382-П, где было упомянуто прикладное ПО для осуществления перевода денежных средств, породили разночтения и длительные споры участников рынка об области применения ОУД. Стал популярным вопрос: надо ли проводить работы по ОУД в отношении всех информационных систем, участвующих в переводе денежных средств (например в отношении АБС), или все же речь идет о каких-то наиболее критичных/высокорискованных системах? Впоследствии эти вопросы были разрешены официальной позицией регулятора. Забегая вперед скажем, что требования к работам по ОУД касаются лишь того ПО, которое соответствует одному из двух условий (либо обоим):

  1. ПО распространяется клиентам организации (физическим или юридическим лицам);

  2. ПО доступно через интернет неограниченному кругу лиц (а не закрыто VPN или иными ограничителями).

Рисунок 3. Границы применимости ОУД для приложений финансовых организаций

Рассмотрим, для примера, как эта логика работает для банков. Из п. 4.1 Положения 683-П, которое устанавливает требования к ИБ кредитных организаций, вытекает необходимость работ по ОУД для ПО распространяемого кредитной организацией клиентам для совершения действий в целях осуществления банковских операций, а также {ПО}, обрабатывающего информацию на участках, используемых для приема электронных сообщений, к исполнению в автоматизированных системах и приложениях с использованием {} Интернет . В информационном письме Банка России от 8 июля 2020 г. N ИН-014-56/110, посвященном ОУД, приведена ссылка на Профиль Защиты Прикладного ПО, как на методику проведения анализа уязвимостей (подробнее об этом документе поговорим ниже). В свою очередь в п. 2.3.1 упомянутого Профиля развернуто сформулированы критерии подпадания прикладного ПО под работы в соответствии с ОУД4: клиентское ПО и/или выход в интернет. В упомянутой цитате из профиля находим:

Настоящий ПЗ определяет требования безопасности к ОО. На ОО обрабатывается защищаемая информация на участках, используемых для передачи и приема первичных документов (содержащихся в электронных сообщениях) к исполнению в автоматизированных системах и приложениях с использованием информационно-телекоммуникационной сети Интернет (далее сеть Интернет).

ОО представляет собой прикладное программное обеспечение, предоставляемое поставщиком или разработчиком, которое используется для предоставления клиентам финансовых организаций сервисов и доступа клиентам к услугам дистанционного обслуживания. ОО размещается на технологических участках передачи и приема первичных документов (содержащихся в электронных сообщениях) к исполнению финансовой организацией с использованием сети Интернет. При этом ОО:

- устанавливается в изолированном сегменте сети, сопряженном с сетью Интернет, на инфраструктуре финансовой организации, входит в состав автоматизированной системы финансовой организации и взаимодействует с обеспечивающими компонентами автоматизированных систем (фронт-офисное СПО);

- устанавливается на отдельном устройстве или компоненте инфраструктуры клиента финансовой организации, сопряженном с сетью Интернет, в качестве прикладного программного обеспечения приложения (клиентское ППО).

Таким образом, спор о границах применимости ОУД был разрешен, а широкая формулировка границ применимости, проистекающая из 382-П уйдет в небытие вместе с указанным положением (оно утрачивает силу 01 января 2022 года на основании положения Банка России 719-П). Остается единственный вопрос как быть, если несколько приложений подпадают под требования? Наш ответ неоригинален риск-ориентированный подход и приоритизация проектов по ОУД внутри организации, особенно в условиях жестко лимитированного бюджета. Такую приоритизацию можно выстраивать на основании масштаба финансовых переводов, с учетом количества обрабатываемых персональных данных или исходить из других, менее очевидных соображений, например возможностей команды разработки оказывать поддержку проекту. В любом случае у вас наверняка есть более критичные каналы взаимодействия с клиентами и есть менее критичные. Если бюджет проекта ограничен, а количество различных приложений подпадающих под ОУД велико, самый простой критерий принятия решения - финансовый.

Теперь, когда мы изучили контекст вопроса, определились с границами применимости требований, решили в какой последовательности мы будем прогонять наши продукты через горнило ОУД, давайте поговорим о ключевых особенностях фреймворка и сделаем его обзор.

Общие положения и концепции ОУД4

В общих чертах фреймворк ОУД можно рассматривать как разновидность SDLC, в рамках которого у нас возникает стандартный набор этапов жизненного цикла продукта, типичный для подобных фреймворков. Их сопровождают популярные концепции, такие как: среда функционирования, функция безопасности, управление конфигурациями и другие.

Ключевыми документами, для понимания фреймворка, являются упомянутые в ссылках ГОСТы, которые не только вводят терминологию, но и содержат многочисленные разъяснения и примеры его различных аспектов. Ниже перечень, на наш взгляд, наиболее интересных и полезных:

  1. ГОСТ 15408-1-2012

  2. ГОСТ 15408-2-2013;

  3. ГОСТ 15408-3-2013;

  4. ГОСТ 18045-2013;

  5. ГОСТ 57628-2017;

  6. ГОСТ Р 58143-2018.

Общий процесс разработки и тестирования, согласно фреймворку, описывается в первой части ГОСТ 15408. В общем случае жизненный цикл продукта может быть представлен так, как показано на рисунке ниже.

Рис 4. Управление конфигурацией и жизненный цикл продукта (согласно ГОСТ Р 15408-1-2012)

Этапы работ, формирующих ОУД, описываются в третьей части стандарта ГОСТ 15408, как показано на следующем рисунке.

Рис 5. Компоненты, формирующие ОУД

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

  1. Ключевых концепций и ролей;

  2. Базовых процессов (взаимодействий) и их результатов.

На базовом уровне можно выделить три ключевые роли:

А. Заказчик (может совпадать с пользователем или владельцем), который использует некий продукт и требует соответствие этого продукта неким установленным требованиям к ИБ;

Б. Разработчик, который создает этот продукт и выстраивает его жизненный цикл, в соответствии с требованиями Заказчика;

В. Оценщик, который проверяет соответствие разработанного продукта установленным требованиям.

Здесь нужно сделать оговорку, что несмотря на методологическую рекомендацию разделять описанные выше роли между субъектами во избежании конфликта интересов (например, чтобы не проверять самих себя, а привлекать третью, независимую сторону), на практике, в некоторых случаях, такое совмещение ролей допустимо и легально. Например, в последнем абзаце п. 9 Положения 684-П сказано, что анализ уязвимостей по требованиям к ОУД4 может проводиться некредитными финансовыми организациями самостоятельно, без привлечения третьей стороны (для сравнения в текущей редакции 683-П такого пункта нет, и подобные работы необходимо осуществлять с привлечением сторонней организации лицензиата ФСТЭК).

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

Какие же процессы и взаимодействия возникают в ходе работ в соответствии с фреймворком ОУД? Практически каждый процесс ИБ начинается с описания границ проекта и требований, безопасная разработка не исключение.


В общих чертах фреймворк декларирует следующую последовательность действий:

  1. Разработать документацию и политики на продукт, которые регламентируют требования к ИБ приложения и разработки;

  2. Обеспечить практическое применение документов в разработке конкретного продукта;

  3. В ходе тестов, оценки соответствия и/или анализа уязвимостей подтвердить, что установленные на уровне документации и политик требования выполняются де-факто и позволяют достичь необходимого уровня безопасности (по сути защитить продукт от нарушителя ИБ с определенным потенциалом).

Ключевым элементом фреймворка является объект оценки (или ОО, например, ДБО, или какой-то компонент внутри ДБО), к которому предъявляются функциональные требования к безопасности (или ФТБ, например, необходимая реализация системы управления доступом или стойкая криптография), формулируемые в задании по безопасности или профиле защиты (разница между двумя в том, что задание по безопасности обычно создается Заказчиком самостоятельно, под себя; а профиль тиражируется различными институциями как минимально-адекватный стандарт для какого-то класса решений, например для межсетевых экранов или антивирусов). Так как объект оценки существует не в вакууме, а актуальные уязвимости связаны не только с разработкой и проектированием, но и с настройкой и эксплуатацией объекта, важными понятиями являются среда функционирования и конфигурация среды/объекта оценки. Наконец, сам оценочный уровень доверия представляет собой гамбургер из большего или меньшего набора компонент, в зависимости от выбранного уровня (смотри рисунок 5 выше).

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

Такое подтверждение может осуществляться с помощью двух базовых сценариев:

  1. С помощью сертификации (делается специализированными лабораториями, включенными в систему ФСТЭК);

  2. С помощью оценки соответствия или анализа уязвимостей (делается самостоятельно для себя, либо сторонней организацией с лицензией ФСТЭК на ТЗКИ).

Это разделение нашло свое отражение в упомянутых по тексту положениях Банка России. В порядке убывания сложности и цены указанные сценарии можно разместить следующим образом:

  1. Сертификация;

  2. Оценка соответствия;

  3. Анализ уязвимостей.

Разница между оценкой соответствия и анализом уязвимостей наглядно иллюстрируется рисунком 5. В первом случае необходима именно оценка соответствия, по множеству компонентов, формирующих указанный ОУД - по сути оценка всего SDLC. Во втором проработка лишь одного компонента, который зависит от построения SDLC, но является лишь малой частью того, что составляет целый ОУД.

При всех нюансах и вариациях имплементации необходимый минимум документации на приложение включает в себя:

  1. Описание архитектуры безопасности;

  2. Функциональные спецификации;

  3. Руководство пользователя по эксплуатации;

  4. Представление реализации;

  5. Проект объекта оценки;

  6. Задание по безопасности.

Для начала такого состава документов нам хватит. Что же касается качества реализации фреймворка и надежности заключений Оценщика, то независимо от выбранного сценария работ, это во многом зависит от соблюдения Заказчиком и Разработчиком установленных семейством 15408 пререквизитов. От выстроенного в организации SDLC и наличия проработанной документации на конкретный продукт. Здесь действует правило аналогичное любому типу анализа защищенности чем более прозрачным для проверяющих будет ПО, чем полнее окажутся его описания, чем более компетентным и проактивным будет Заказчик, тем больше недостатков и уязвимостей смогут найти проверяющие и тем качественнее окажутся их заключения. Увы, в реальной жизни, в силу дороговизны работ и сложности процесса, указанные выше пререквизиты часто либо отсутствуют, либо находятся в зачаточном состоянии.

Заключение

Это наш первый опыт популярного изложения вопросов комплаенса (или соответствия стандартам) для широкой публики и нам важно получить обратную связь, чтобы адаптировать будущие тексты под интересы читателей и сделать их полезнее. Расскажите, пожалуйста, в комментариях - что вам понравилось в первой статье цикла, а что нет? Какие специфические темы, вопросы или примеры из жизни вы бы хотели подробно разобрать в контексте темы цикла? А может быть вы уже активно работаете с ОУД и хотите поделиться решенными проблемами, замечаниями и наблюдениями? Помимо упомянутой во введении методички по вопросам ОУД, мы планируем серию сопутствующих вебинаров, содержанием которых могут стать ответы на ваши вопросы и демонстрация реальных кейсов внедрения фреймворка. Для желающих приватности адрес электронной почты для связи: aantonov@swordfishsecurity.com

Полезные ссылки и материалы по теме:

  1. https://malotavr.blogspot.com/ блог Дмитрия Кузнецова, эксперта Positive Technologies, одного из немногих специалистов, систематически рассматривающих вопросы сертификации ПО и анализа уязвимостей по ОУД4. Написал несколько материалов про требования ЦБ и ОУД4, см. статьи за 2019 год.

  2. https://www.youtube.com/watch?v=0ZoNdaoAeyc&t=658s обзорный вебинар компании RTM Group, посвященный особенностям фреймворка, с участием компании Safe Tech, описывающий реализацию фреймворка в отношении своего продукта.

  3. Переведенные стандарты:

    a. ГОСТ 15408-1-2012;

    b. ГОСТ 15408-2-2013;

    c. ГОСТ 15408-3-2013;

    d. ГОСТ 18045-2013;

    e. ГОСТ 57628-2017;

    f. ГОСТ Р 58143-2018.

  4. https://en.wikipedia.org/wiki/Common_Criteria Обзор лучших практик по безопасной разработке статья в вики для желающих самостоятельно углубиться в исторические предпосылки.

  5. Лучшие практики безопасной разработки:

    a. https://doi.org/10.6028/NIST.CSWP.04232020 обзор актуальных практик SDLC от американского института NIST Mitigating the Risk of Software Vulnerabilities by Adopting a Secure Software Development Framework (SSDF) от 23.04.2020;

    b. https://www.iso.org/standard/55583.html стандарт ISO/IEC 27034-3:2018 Information technology Application security Part 3: Application security management process;

    c. https://www.pcisecuritystandards.org/document_library стандарты PCI SSC линейки Software Security Framework:

    i. Secure Software Requirements and Assessment Procedures;

    ii. Secure Software Lifecycle (Secure SLC) Requirements and Assessment Procedures.

  6. https://www.cbr.ru/information_security/acts/ Методический документ Банка России ПРОФИЛЬ ЗАЩИТ прикладного программного обеспечения автоматизированных систем и приложений кредитных организаций и некредитных финансовых организаций.

Приложение (список сокращений)

По тексту документа использованы следующие сокращения/условные обозначения:

  1. 382-П/Положение 382-П Положение Банка России от 9 июня 2012 г. 382-П О требованиях к обеспечению защиты информации при осуществлении переводов денежных средств и о порядке осуществления Банком России контроля за соблюдением требований к обеспечению защиты информации при осуществлении переводов денежных средств (актуальная редакция от 07.05.2018, действительно до 01.01.2022 года, отменяется 719-П);

  2. 719-П/Положение 719-П Положение Банка России от 4 июня 2020 г. 719-П О требованиях к обеспечению защиты информации при осуществлении переводов денежных средств и о порядке осуществления Банком России контроля за соблюдением требований к обеспечению защиты информации при осуществлении переводов денежных средств;

  3. 672-П/Положение 672-П Положение Банка России от 09.01.2019 N 672-П О требованиях к защите информации в платежной системе Банка России;

  4. 683-П/Положение 683-П Положение Банка России от 17 апреля 2019 г. N 683-П Об установлении обязательных для кредитных организаций требований к обеспечению защиты информации при осуществлении банковской деятельности в целях противодействия осуществлению переводов денежных средств без согласия клиента;

  5. 684-П/Положение 684-П Положение Банка России от 17.04.2019 N 684-П Об установлении обязательных для некредитных финансовых организаций требований к обеспечению защиты информации при осуществлении деятельности в сфере финансовых рынков в целях противодействия осуществлению незаконных финансовых операций;

  6. 162-ФЗ/Федеральный закон 162 ФЗ Федеральный закон О стандартизации в Российской Федерации от 29.06.2015 N 162-ФЗ;

  7. АБС автоматизированная банковская система;

  8. ГОСТ Р национальный государственный стандарт Российской Федерации;

  9. ИБ информационная безопасность;

  10. ИТ информационные технологии;

  11. ОО объект оценки;

  12. ОУД оценочный уровень доверия (см. ГОСТ/МЭК 15408);

  13. ПО программное обеспечение, приложение;

  14. Фреймворк здесь тоже самое, что стандарт, задающий структуру вокруг которой выстраивается какой-либо процесс или решение задачи;

  15. ISO/IEC International Organization for Standardization(ISO) and theInternational Electrotechnical Commission(IEC);

  16. SDLC - Software Development Lifecycle.

Соавтор: (Рустам Гусейнов, специалист по информационной безопасности).

Подробнее..

Как в MGA в 5 раз быстрее реализуют проекты при помощи GitLab

11.01.2021 12:12:41 | Автор: admin


Как в MGA в 5 раз быстрее реализуют проекты при помощи GitLab


Благодаря переходу на GitLab в MGA внедрили практики CI/CD, повысили качество ПО, создали процесс обмена знаниями и сэкономили средства.


Oбзор

В MGA перешли на GitLab с целью улучшения качества и сокращения сроков разработки с использованием автоматизированных процессов CI/CD.

Трудности

В MGA искали экономичную Continuous Integration платформу, которая позволила бы усовершенствовать рабочий процесс, расширить знания и повысить качество кода.

Pешение

GitLab EE

Преимущества

  • Автоматические сканеры кода в конвейере CI
  • Улучшенные возможности совместной работы
  • Повышение эффективности операционных процессов
  • Улучшение качества продуктов
  • Простота интегрирования

C 80 до 240 Увеличение объема проектов


10 В 10 раз больший коэффициент успешного выполнения, чем при ручном развертывании CD


80% Экономия времени при переходе на CD


Kлиент Разработчик корпоративного логического ПО


MGA разрабатывает, создает и внедряет компьютерные приложения для крупных и средних коммерческих и промышленных предприятий. Компания MGA, основанная в 1993 году, создала логическое программное обеспечение, которое использует преимущества реляционной базы данных (Oracle), работающей на операционной системе Linux. В 1999 году MGA создала подразделение аутсорсинга и начали предоставлять бухгалтерские услуги, кадровую поддержку и услуги по расчету заработной платы более чем 30 компаниям.

Tрудности Недостатки в совместной работе, поддержке и качестве кода


В MGA сами писали код и использовали Mercurial. Команда разработчиков протестировала бесплатные инструменты, которые позволяли проверять код и поддерживали CI и CD. Это оказалось сложным процессом, так как у программистов не было опыта в использовании подобных инструментов, а поддержка при их установке и применении не предоставлялась. У MGA возникли серьезные проблемы, поскольку Mercurial был слишком сложным, а у разработчиков не хватало опыта в использовании инструментов CI/CD.

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

Из-за невозможности совместной работы и отсутствия общего доступа к документации снижалось качество кода. Мы начали искать инструменты, которые позволяли бы нам просто осуществлять проверку кода и создавать политику утверждения для управления кодом. Вторым приоритетом было системное использование CI/CD с целью упростить работу и свести к минимуму штат администраторов, рассказывает главный ИТ-администратор Якуб Тадея.

У команд также возникали проблемы с распределением знаний. В MGA справочная информация хранилась на внутренних вики-сайтах, в задачах Redmine, записях от руки и некоторых приложениях. Ресурсы были разрозненны, неорганизованны и их было трудно найти. Новым сотрудникам приходилось самостоятельно разыскивать документацию о внутренних системах. ИТ-специалисты и разработчики MGA теряли время и деньги, не имея подходящих инструментов для решения всех проблем.

Pешение Динамичный инструмент по выгодной цене


В MGA протестировали различные инструменты. Обнаружив простой пользовательский интерфейс GitLab, в компании приняли решение перейти с Mercurial на GitLab. Еще одним аргументом в пользу GitLab был Deviniti официальный партнер GitLab в Польше. Проработав неделю с этим хорошо зарекомендовавшим себя партнером, в MGA окончательно решили продолжить работу с GitLab. Для покупки MGA требовалась польская валюта и польские счета. Большинство польских клиентов ищут местного партнера, который сможет продавать им продукцию, поясняет директор по продажам Deviniti Радослав Косец. Поддержка и знания местных особенностей со стороны Deviniti способствовали быстрому переходу MGA на новую платформу. В MGA до сих пор очень довольны партнерством. Работать с Deviniti одно удовольствие. Рекомендую!, добавляет Тадея.

Тарифный план GitLab подходил MGA больше всего. Это стало важным фактором в принятии окончательного решения. Мы зарабатываем меньше, чем компании на Западе Мы искали решение, которое бы позволило размещать приложения на нашем сервере. Насколько мне известно, GitHub и прочие облачные решения не позволяют этого сделать. Их невозможно использовать локально, поясняет Тадея.

До начала использования GitLab программисты работали в небольших командах над мелкими проектами. Но по мере роста компании увеличивались объемы проектов и численность команд. Внедренные инструменты уже не справлялись с такими масштабами. Благодаря GitLab, создание наших проектов полностью изменилось, утверждает Тадея. Первоначально у нас не было больших ожиданий. Нам просто был нужен новый инструмент, который дает возможность создавать конвейер CI/CD и политику проверку кода. Большего мы не ждали. Однако, как выяснилось, GitLab может предложить намного больше. Постепенно мы начали экспериментировать с функциями, и нам понравилось.

Благодаря GitLab, команды смогли планировать дорожную карту ПО и устанавливать сроки окончания проектов. Мы начали планировать проекты, используя непрерывную интеграцию и развертывание. GitLab полностью изменил архитектуру нашего решения, говорит Тадея.
У CD как минимум в 10 раз больший коэффициент успешного выполнения, чем у развертывания вручную. У нас есть проекты, где ни разу не подвело автоматическое развертывание. Якуб Тадея, Главный ИТ-администратор

Pезультаты Лучшие программы, больше разработчиков и единая база знаний


Успех с самого начала все шло как по маслу. В этом было самое большое преимущество, потому что мы легко установили GitLab и обновили его. Начать работу было очень просто, рассказывает Якуб. Подготовка серверов к переходу на GitLab заняла у MGA примерно неделю. В течение года все проекты перенесли в новый инструмент. Было очень просто начать работу. У нас не возникало никаких проблем, добавил Тадея.

До перехода на GitLab было 3 ИТ-администратора и 30 разработчиков. Теперь у нас более 60 разработчиков, которых легко обслуживают три ИТ-администратора, и много других серверов. Задержки больше не возникают, поскольку большая часть проблем больше не ложится на плечи ИТ-администраторов.

С начала использования GitLab количество проектов увеличилось с 80 до 240. В запущенных проектах все выполняется через CI и CD. По мере необходимости мы просто решаем проблемы и учим разработчиков пользоваться инструментами GitLab, поясняет Тадея. Теперь наша работа более эффективна, и мы можем уделять больше внимания коду, не отвлекаясь на простейшие задачи, которые можно автоматизировать.

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

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

Благодаря поддержке GitLab, MGA быстрее создает более качественные программы, улучшив процессы тестирования и проверки качества кода. ИТ-специалисты и команды разработчиков стали специалистами в области CI/CD и создают оптимизированные системы автоматизации, при этом сводя к минимуму потребности в ИТ-администрировании и повышая эффективность затрат.

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

Тонкости настройки CICD как работает GitLab runner, когда использовать Docker-in-Docker и где пригодится Argo CD

21.01.2021 08:19:12 | Автор: admin


В конце прошлого года в Слёрме вышел видеокурс по CI/CD. Авторы курса инженер Southbridge Александр Швалов и старший системный инженер Tinkoff Тимофей Ларкин ответили на вопросы первых студентов.


В частности, обсудили:


  • Как работает GitLab runner: сколько задач берёт и сколько ресурсов потребляет, где его лучше размещать и как настроить шаринг между проектами?
  • Как настраиваются пайплайны для проектов в монорепозитории? А как в ситуации, когда для каждого микросервиса свой репозиторий?
  • Как бороться с тем, что во время сборки артефакта в Docker очень быстро забивается свободное место на диске?
  • Когда лучше использовать подход Docker-in-Docker?
  • Как организовать доставку и развёртывание сервисов в закрытые окружения заказчика?

Видео с ответами на вопросы смотрите на YouTube. Под катом текстовая версия разговора.


С версии 20.10 Docker Engine стал rootless. Раньше эта фича была экспериментальной, а теперь оказалась в проде. Изменится ли что-то с точки зрения безопасности и сборки Docker-образов без root-привилегий?


Тимофей Ларкин: Я не думаю, что это сильно на что-то повлияет. Возможно, они идут к тому, чтобы появился отдельный сборщик образов от Docker. Но пока мы используем Docker-in-Docker, и, скорее всего, этот Docker-in-Docker в режиме rootless просто не будет запускаться.


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


Александр Швалов: В документации Gitlab есть открытый баг (issue), мол, давайте включим режим rootless, но официальной поддержки пока нет. Для сборки поддерживается kaniko, и мы добавили пример с kaniko в наш курс.


Дайте пример реального размещения репозиториев с кодом, секретами и helm-чартами где всё должно лежать в жизни? Как выглядит по умолчанию шаблон? Боевой deployment.yml не должен быть в репозитории сервиса?


Тимофей Ларкин: Ответ на такие вопросы всегда it depends зависит от ситуации. Если это open source проект, то там может и не быть деплойментов, там может быть makefile, который покажет, как собрать артефакт, как из него собрать Docker-образ. Но это репозиторий на Github, в лучшем случае он через github actions делает регулярные билды и кладёт их на Docker Hub или другой репозиторий образов контейнеров. Оно и понятно: это просто open source проект, куда его деплоить.


Другое дело, если это проект, который вы деплоите на инфраструктуре: своей, облачной неважно. Например, это приложение, которое разрабатывается и используется у вас в компании. Действительно, довольно простой способ держать и код, и скрипты сборки артефактов, и какой-нибудь helm-чарт в одном репозитории. Разнести по разным папкам, а GitLab CI будет и собирать, и сохранять артефакты, и пушить изменения в Kubernetes.


Подход не очень масштабируемый: когда приложений много, становится тяжело отслеживать, что задеплоено в Kubernetes. Чтобы решить проблему, подключают сервисы вроде Argo CD, а код и описание конфигурации хранят в разных репозиториях. Деплоят через CI (push-модель) или через кубы в Argo.


Когда компания занимается заказной разработкой, всё ещё сложнее. Встаёт вопрос, как деплоить код на инфраструктуру заказчика, и готов ли он принять Continuous Deployment исполнителя или хочет больше контроля? Надо смотреть на специфику.


Александр Швалов: У каждой команды свои стандарты, некоторые сложились исторически, некоторые появились на основе шаблонов или документации. В нашем курсе по CI/CD есть примеры, они рабочие можете адаптировать под свой проект. Исходите из своих потребностей.


Есть ли краткий справочник по полям gitlab-ci файла?


Александр Швалов: Краткого справочника нет, если нужна конкретная фича, лучше идти в документацию и смотреть, что там есть. Ну а базовые принципы как из большого набора кирпичиков собрать свой gitlab-ci.yml вы можете почерпнуть из курса или документации. Если в курсе нет, в документации точно будет.


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


Как можно привязать Jira к GitLab?


Александр Швалов: У бесплатной версии GitLab есть интеграция с Jira, ищите в соответствующем разделе.


Тимофей Ларкин: Более того, мы работали одновременно с двумя issue-трекерами: все проекты вязались в Jira, но отдельные команды настраивали для своих репозиториев привязку к YouTrack. Это было не очень удобно, потому что надо было ходить по каждому репозиторию, который хочешь привязать. Но да, такая функциональность действительно есть даже в бесплатном GitLab.


Почему joba release триггерится при изменении тега, хотя в родительском пайплайне стоит only changes?


Александр Швалов: Я провёл небольшое исследование и выяснил: это не баг, это фича. В GitLab был заведён баг, и его закрыли с комментарием, что так задумано. Если вам нужно обойти это поведение, используйте один из двух вариантов, которые предлагает GitLab.


GitLab не обновляет статусы дочерних пайплайнов. Что с этим делать?


Александр Швалов: А вот это уже баг. Возможно, когда-нибудь починят.


Есть ли в GitLab профили переменных? Например, я хочу сделать переменную host, и чтобы она приезжала разная в зависимости от окружения. Есть ли какое-нибудь профилирование? Например, я не хочу называть переменную host_dev, host_prod и host_test, а хочу указать окружение, и оно определённый набор переменных вытащит? Можно ли такое сделать?


Тимофей Ларкин: С ходу на ум мало что приходит. Можно, наверное, какие-то env-файлы держать в репозитории и просто их сорсить в пайплайне.


Нормальная практика называть host_dev, host_prod, host_test и т. д?


Александр Швалов: Скорее всего, есть встроенные переменные. Если у вас описано разделение по окружениям, то встроенная переменная будет знать, как называется окружение.


Тимофей Ларкин: Я не сталкивался с таким наименованием переменных. Это кажется оправданным, только если один пайплайн должен работать одновременно с несколькими разными окружениями. Если просто хочется разного поведения пайплайна в зависимости от ветки или чего угодно ещё


У меня в пайплайне может быть стадия deploy и стадия release, и тогда эти переменные должны быть разные, иначе как?


Тимофей Ларкин: То есть сначала один job деплоит на stage, а потом следующий job деплоит на prod?


Нет, job, который на prod работает, он срабатывает, когда only text. Всё это описано в одном пайплайне.


Тимофей Ларкин: Я решал это ямловскими (YAML прим. редактора) якорями, у меня были очень однотипные jobы из трёх строчек. Или можно теми же extends, как в примере с Docker. А дальше в каждом job пишешь свой блок variables, поэтому основное тело jobа работает с одними и теми же скриптами, но в зависимости от значения переменной host или переменной environment, оно деплоит на разное окружение.


Мы не имеем разные переменные для разных jobов, мы используем одни и те же названия переменных, просто с разными значениями. Возможно, оправдано в репозиторий поместить какие-то скрипты, которые сами внутри себя это разруливают, чтобы не раздувать gitlab-ci.yml.


SSH executor создаётся по одному на сервер?


Тимофей Ларкин: Фактически да. Можно, разве что, поставить какой-нибудь tcp-балансировщик и рандомно попадать на тот или иной сервер.


Имеет смысл разделять раннеры, которые деплоят на test и staging, и раннеры, которые деплоят на prod?


Тимофей Ларкин: Наверное, можно. Действительно, запустить раннеры в разных сетевых сегментах, которые не могут общаться друг с другом. В моей практике это не было нужно. У нас была ориентированная на Kubernetes система, а если речь идёт про SSH на тот сервер, SSH на этот сервер наверное, это будет оправдано.


В Kubernetes вы, наверное, по разным namespace деплоили и всё?


Тимофей Ларкин: Да, но при этом все раннеры в одном и том же месте запускались. Был отдельный namespace для раннеров.


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


Тимофей Ларкин: Необязательно, это зависит от того, какой executor работает.


Александр Швалов: Есть параметр concurrency. Если раннер один и идёт долгий пайплайн, то получается, что остальные девелоперы сидят и курят бамбук мы такое проходили, и для обхода настраивали concurrency. В зависимости от ресурсов раннера: сколько jobов он потянет одновременно, можно настраивать.


Он под каждую jobу своё окружение создаст?


Тимофей Ларкин: Да, он либо свой инстанс в bash запустит, либо несколько SSH-подключений, либо несколько Docker-контейнеров или подов в Kubernetes.


Есть ли в Argo CD и других GitOps-инструментах возможность параметризации реакции на изменения? Например, обновлять prod окружение, только если мастер + тэг или если фича, то в dev окружении менять состояние/производить обновления?


Тимофей Ларкин: В вопросе есть очень распространённое заблуждение, я и сам на нём спотыкался. Надо запомнить: не бывает, чтобы у нас был тег на мастер-ветке. Тег никогда на ветке не бывает. Где-то в GitLab даже есть issue, который это очень подробно объясняет. Но это лирическое отступление.


В принципе, Argo CD может что-то похожее сделать. Но надо понимать, что он не совсем про это. Его основная и довольно простая функция это чтобы в таком-то месте (namespace или кластере Kubernetes) была задеплоена такая-то ветка, такой-то тег определённого репозитория.


Как мне показалось, в вопросе речь была о пайплайнах и CI/CD. Но это не основная функциональность Argo, и кажется, он такого не поддерживает. Можно посмотреть на другие GitOps-инструменты. По-моему, у werf от Фланта есть функционал отслеживания что там меняется в Docker-репозитории. Но в целом GitOps это не совсем про это. Вот как в гите опишите, то и будет задеплоено.


На коммит Argo увидит: О! Что-то поменялось, значит надо поменять это и в Kubernetes, но без какой-то сильно ветвистой логики.


Александр Швалов: Я добавлю, что тэг это не ветка, а по смыслу ближе к коммиту. Тут поможет семантическое версионирование, и можно настраивать шаблоны для Argo CD. Если для продакшена, то конкретный релиз: 1.2.0, 1.2.1. Для stage будет 1.2. любая циферка в конце приедет на stage. Для QA это 1. всё остальное приедет. Для совсем свежего, для локальной разработки просто звёздочка *, любой тег Argo CD будет сразу подтягивать.


Какой сканер посоветуете для Docker-образов? Мне trivy понравился, но может что удобнее есть?


Александр Швалов: Я использовал Trivy, нареканий не было.


Как настраиваются пайплайны для проектов в монорепе, и как в ситуации, когда для каждого микросервиса свой репозиторий?


Александр Швалов: Возможно, мы добавим такой пример в курс. Спасибо за запрос! Вообще, ходят слухи, что у Google и Microsoft всё хранилось или хранится в монорепах миллиарды строк кода. Здесь многое зависит от человеческого фактора, а не от инструментов. Если говорить о GitLab CI/CD, то всё просто: в шаге сборки какой-то части, например, фронтенда используем only changes, выбираем каталог и дальше поехали. Что-то изменилось, GitLab производит деплой. С тестами будет посложнее, потому что фронтенд (или какая-то часть, особенно, если это микросервисы) запустится и будет неполноценным. Поэтому для тестов придётся поднимать минимальные зависимости.


Тимофей Ларкин: Я не видел open source систем контроля версий, которые поддерживают такую модель работы, как монорепозиторий. У больших игроков свои системы, и разработчики даже рассказывают: Вот, я работал в Google/Amazon/Facebook, а потом я ушёл оттуда, пошёл в среднего размера компанию, и я не знаю, что делать. Нигде нет магии этих больших систем, которые сами решают все проблемы с версионированием кода. Внезапно я должен работать с тем же GitLab.


Поэтому если вы не огромная корпорация с ресурсом написать свою систему контроля версий, то можно костылить пайплайны, чтобы они были как монорепозитории писать кучу only changes на различные куски. До каких-то масштабов это, наверное, будет работать. Взять тот же Kubernetes, который выпускает свои известные 5 бинарей (и даже чуть больше) с параллельным версионированием. Нет такого, что один компонент в своём репозитории, другой в своём, и у них свой набор версий. Нет, они выпускаются из одного репозитория, поэтому у них хэши комитов, теги и всё остальное одинаковое. Да, так можно работать. Go позволяет собирать несколько бинарников из одного модуля, но в целом так не очень легко работать. Для какого-то проекта да.


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


Ну и как всегда: если хотите оставаться в парадигме один репозиторий один микросервис, тогда где-то храните метаданные (какой хеш коммита соответствует какому тегу, какому релизу) и с помощью Argo оркестрируйте всё это.


Какие существуют best practices по размещению раннеров? Как лучше организовать размещение нескольких раннеров на одной машине, чтобы можно было добавлять новые? Стоит ли размещать раннеры в Docker-контейнерах, или лучше использовать виртуальные машины, например, kvm?


Александр Швалов: GitLab для раннеров по запросу предлагает использовать Docker Machine, и соответственно использует драйверы оттуда это всяческие облака и виртуализации (AWS, Azure, VirtualBox, Hyper V, vmWare). KVM в списке нет. Для множественных раннеров можно настраивать также шареный кэш. Например, в AWS S3 хранилище.


Однако этот подход через Docker Machine сам GitLab считает малость устаревшим. Есть открытый баг, где разработчики размышляют, куда лучше перейти, какие-то варианты есть. Самый очевидный перейти в Kubernetes. Ну а best practice в общем не размещать раннер на одном хосте с GitLab, чтобы они друг друга не аффектили. Ну и на продакшене раннер тоже лучше не размещать, потому что вдруг туда что-то прилетит критичное.


Для небольших проектов достаточно одного раннера (на своих проектах я так и делал). Просто настроить ему concurrency, чтобы разработчики не стояли в очереди друг за другом, и дать какое-то количество процессора и памяти, настроить опытным путём и так жить.


Тимофей Ларкин: Когда мы пайплайны гоняли в Kubernetes, то мы просто на несколько хостов вешали taint с эффектом PreferNoSchedule, чтобы пользовательские нагрузки приложения запускались преимущественно где-то на других хостах. Но при этом на раннеры мы вешали nodeSelector как раз на эти же самые хосты. Это к вопросу о разделении нагрузки от приложения и нагрузки от раннера.


Да, есть беда, что у сборок совершенно другой профиль нагрузки, чем у обычных приложений. Как правило, сборка это хорошая нагрузка на CPU (обычно именно на CPU, а не на память). Затем идёт сборка Docker-образа, (если мы более-менее всё аккуратно делаем: сначала собрали артефакт, затем его как артефакт передали в следующий этап пайплайна, а затем в Docker-образ кладём готовые бинарники), то идёт нагрузка на диск, потому что там все эти слои формируются, пишутся и, наконец, после этого мы загружаем сеть, перекачивая собранный Docker-образ в наш registry.


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


С Kubernetes всё понятно. Мне даже хотелось убрать раннеры из Kubernetes и где-то отжать два хоста, которые использовать как build-серверы, чтобы совсем всё отдельно было. Всякие деплои, понятно, это очень легковесная задача. Запушить ямлик в Kubernetes никаких ресурсов не требует. Ну а если у нас SSH или shell-раннер, то тогда сама ситуация диктует, где их размещать. А если вопрос про бинарь GitLab Runner, то он очень мало ресурсов потребляет, его можно где угодно расположить. Тут больше зависит от требований сетевой доступности.


Когда лучше использовать подход Docker-in-Docker? Какие еще есть инфраструктурные идиомы, связанные с GitLab?


Александр Швалов: Скажу очевидную вещь: использовать Docker-in-Docker стоит, когда у вас сам раннер запущен в Docker. Ну а если у вас нужно запускать какие-то команды в Docker как это задумывалось вообще: если раннер запущен в Docker, то вы можете просто в Docker-in-Docker брать другой Docker-образ (Python, например, и в нём выполнять какие-то действия из кода).


Тимофей Ларкин: Я буду чуть более категоричен. Docker-in-Docker стоит использовать почти никогда. Бывают случаи, когда мне надо собрать кастомный образ kaniko, но когда я пытаюсь собрать его через kaniko, то всё уходит в бесконечную рекурсию и падает (есть такие интересные особенности). Тогда приходится использовать Docker-in-Docker. Кроме того, Docker-in-Docker можно использовать на какой-нибудь виртуалке, которой мы сделали хорошую изоляцию ото всего, чтобы там вообще нельзя было дотянуться ни до инфраструктуры, ни до ещё чего-то, чтобы там можно было только Docker-образы собирать.


В остальных ситуациях Docker-in-Docker это огромная зияющая дыра в безопасности. Очень легко использовать: у тебя есть root-права, у тебя есть привилегии, ты можешь монтировать хостовую файловую систему. Накатал Dockerfile, в котором первым шагом устанавливаешь SSH-демон, прокидываешь туннель туда куда надо, потом заходишь на эту машину и с root-правами монтируешь на эту машину dev/sda1 и всё, у тебя доступ к хосту, ты делаешь что хочешь.


Александр Швалов: Лучше посмотреть в сторону новомодных Podman, Buildah и kaniko. Совсем недавно были новости, что Kubernetes хочет отказаться от Docker все схватились за голову, но это в принципе ожидаемо. И сам Docker (мы с этого начали) уже выкатил rootless mode. Поэтому всеми силами стоит уходить от выполнения от root.


Как можно бороться с тем, что когда происходит сборка артефакта в Docker, очень быстро забивается свободное место на диске (ну кроме docker prune -a)?


Александр Швалов: Только одно решение выделить больше диска, чтобы хватало этого запаса на тот период, когда у вас срабатывает по расписанию сборка мусора. Либо использовать одноразовые раннеры где-то в облаках.


Тимофей Ларкин: Регулярно подчищать за собой: docker prune -a. Совершенно точно плохая практика использовать хостовый Docker-демон для этих сборок. Потому что доступ к хостовому демону это огромная дыра в безопасности, мы можем делать всё что угодно на хосте от имени рута. Ну и плюс, если мы для сборки используем хостовый Docker-демон, то он моментально забивается всяким мусором.


Допустим, даже не используя никакой хостовый Docker-демон, даже имея политику подчистки Docker-образов в GitLab registry, когда мы только стартовали, у нас был раздел под GitLab на 250 Гб. Потом мы стали упираться, сделали отдельный раздел под GitLab на 250 Гб, а под GitLab registry ещё один на 250 Гб. У нас GitLab Omnibus подключал два persistent volume одновременно. Потом раздел под registry разросся до 500 Гб, сейчас он, кажется, 750 Гб и надо узнать у бывших коллег, что у них там происходит хватает места или надо ещё что-то придумывать. И это при том, что есть политика удаления всех, кроме последних пяти тегов какого-то образа. И это без всяких артефактов сборок, это просто конечные образы, которые дальше запускаются на каких-то окружениях.


Как организовать мирроринг стороннего репозитория (например, из GitHub) в GitLab средствами самого GitLab? То есть чтобы автоматически в GitLab подтягивались все изменения, обновления из стороннего репозитория, новые теги и т. д. Без необходимости периодически делать pull руками, без использования скриптов или сторонних решений для автоматизации этого процесса. Если нельзя обойтись без сторонних решений, то какое из них вы бы порекомендовали?


Александр Швалов: Сразу скажу, что полная поддержка этой функциональности есть в платной версии Starter. Для ускорения автоматики можно дополнительно использовать вебхуки в GitHub, чтобы он при каждом чихе тыкал палочкой в GitLab и GitLab в ответ на это делал pull из GitHub. Если надо обойтись исключительно бесплатной версией, то мне не приходилось этим заниматься, скорее всего, придётся использовать дополнительные сторонние скрипты. Сходу можно порекомендовать настроить для этого CI/CD пайплайн: грубо говоря, можно делать операции с гитом на уровне раннера и запускать это всё по расписанию. Но это, конечно, костыль.


Тимофей Ларкин: Я бы не брал этот подход. Это очень способствует плохим практикам. Чаще всего проблемы возникали, когда мы работали с внешними подрядчиками, которые упорно не хотели хранить свой код в нашем GitLab, а хранили его в своём. Поскольку это большая корпорация, собственные TLS-сертификаты самоподписные и так далее, то подрядчик не знает, как их себе в системное хранилище добавить, или ещё какая-то беда в результате всегда было довольно тяжело получить от подрядчика не просто артефакт, а код. Потому что а зачем? а мы попытаемся помиррорить! не работает ладно, тогда будем на своём GitLab работать. Возможно, есть ситуации, когда это важная и нужная функциональность, но частенько это абьюзится.


Какой аппаратный ресурс наиболее востребован для инстанса GitLab в docker-контейнере: процессор, оперативная память или хранилище? А для раннеров?


В случае, если есть только один мощный сервер с мощным процессором, большим объемом оперативной памяти и большим хранилищем и еще один-два сервера меньшей мощности с процессорами послабее, как наиболее оптимально задействовать первый сервер для развертывания GitLab-инфраструктуры
(то есть самого GitLab и раннеров) и что лучше перенести на сервера меньшей мощности? Как целесообразно в этом случае размещать раннеры: в Docker-контейнерах на хосте или в виртуальных машинах (например, kvm)?
Ориентировочная нагрузка на инстанс GitLab: 100 пользователей, 200 проектов.


Александр Швалов: Как адепт классических решений, я бы предложил KVM как более проверенное решение. Docker-контейнеры для меня это до сих пор что-то эфемерное: сейчас запустил, через 15 минут можно грохнуть. GitLab же должен работать и работать, там вы храните свою конфигурацию. Зачем его поднимать, гасить?


Требования по железу есть у самого GitLab. Для 100 пользователей нужно 2 ядра (хватит до 500 юзеров) и 4 Гб памяти (до 100 юзеров). При расчёте объема диска лучше исходить из простой математики: объём всех репозиториев, которые есть, умножить на 2. И не забыть продумать, как вы будете добавлять к серверу новые диски, если репозитории разрастутся.


Железные требования для раннеров предсказать сложно. Зависит от проектов, что вы там собираете: html-страницы или java-код. Надо взять изначальные требования к сборке и от них отталкиваться. Возможно, стоит взять что-то виртуальное, докинуть ресурсов и настраивать по необходимости.


Тимофей Ларкин: Увидев этот вопрос, я специально попросил у коллег графики по потреблению GitLab. Там всё не так весело. Их инстанс GitLab так-то на 500 пользователей, но реально что-то разрабатывают не более 200 человек. Там безупречно ровная полка ну как, колеблется от 1,5 до 2 ядер на протяжении нескольких дней, возможно, по ночам чутка потише. Полка по памяти в районе 50 Гб тоже довольно стабильно.


То есть возвращаясь к рекомендациям: по ядрам, наверное, они реальны, а по памяти занижены. 4 Гб хватит только для запуска, а для активной работы понадобится гораздо больше. И это даже вместе с тем, что базы данных PostgreSQL, которые под этим GitLab, они сейчас живут на отдельных хостах. Раньше, по моим наблюдениям, процессор загружался гораздо сильнее.


Независимо от способа деплоя я бы запустил GitLab на жирном хосте: нам важна надёжность GitLab, многие его компоненты достаточно прожорливы. На других хостах поменьше, наверное, можно было бы гонять Docker executor.


Интересует деплой не в Kubernetes. Допустим, по SSH или же docker\docker-compose.


Александр Швалов: Да, это популярный запрос. Мы планируем добавить это в наш курс (на момент публикации статьи уже добавили прим. редактора) деплой в простой Docker. Всё делается очень просто: раннер с предварительно настроенными ключами заходит по SSH на хост, делает там docker stop, docker rm (удаляет старый контейнер) и docker run с прямым указанием на конкретный образ, который мы только что собрали. В результате поднимается новый образ.


Голый Docker это не оркестратор, и репликации там нет, поэтому при таком CI/CD у вас будет перерыв в обслуживании. Если у вас нет образа контейнера, в моём примере лучше его запустить самостоятельно.


Тимофей Ларкин: Если интересует совсем голый SSH, то пишите скрипты и запускайте. Можем, наверное, минимальный пример в курс добавить. Но надо понимать, что Kubernetes уйму проблем с оркестрацией решает, ну и Docker тоже достаточно можно решает (перезапуски, healthcheck, что угодно).


Если я был вынужден описывать голый SSH, наверное, я бы запускал что-нибудь через systemd. Да, можно Ansible использовать, но опять же, через тот же systemd.


Александр Швалов:Если ещё нет образа контейнера на хосте (я вспомнил, как это у меня делалось), там тоже через Bash проверяется, есть что-нибудь или нет. Если нет, то делаем docker run без всего; docker run, и конкретный образ из registry, который только что создан. Если что-то есть, то сначала останавливаем это всё, и после этого docker run.


Можно ли контейнер с раннером создавать динамически (только на момент сборки)?


Александр Швалов: Да. Очень популярно брать дешёвые инстансы AWS и запускать раннеры там, а потом их глушить по прошествии какого-то времени. Пошла активная сборка, пошёл деплой, насоздавались раннеры и через какое-то время, когда нагрузки нет, они сами по себе схлопнутся. Это всё реализуется через Docker compose.


Тимофей Ларкин: Мы говорим про GitLab runner, который управляющий бинарник, или мы про сами пайплайны? Ну да, пайплайны, наверное. А сам управляющий бинарь? Тогда что будет триггерить создание этого самого бинаря? Опять возникают проблемы курицы и яйца.


Александр Швалов: В Kubernetes, насколько я знаю, можно через какие-то метрики, когда нагрузка есть, он создаёт Так же для OpenShift я нашёл, есть оператор, который управляет раннерами. Как-то можно автоматизировать, люди движутся в этом направлении. Но, как правило, на простых проектах, если что-то нужно, мы берём и виртуалке добавляем ресурсов, а когда проходит час пик убираем ресурсы.


Тимофей Ларкин: Автоскейлинг нод можно делать. Потому что так-то Docker-контейнеры с пайплайнами создаются автоматически только на время существования пайплайна по дефолту. Управляющий бинарь должен существовать по дефолту. Иначе как кто-то узнает, что надо создавать управляющий бинарь?


Как можно настроить шаринг раннера только между определённым количеством проектов?


Александр Швалов: Для этого в GitLab есть группы, создаёте группу, привязываете раннер и в эту группу добавляете проекты. Доступ юзеров, соответственно, распределяется. Всё просто!


Тимофей Ларкин: Ссылка на issue, где описывается, как это делать. Необязательно даже, чтобы это был раннер на группу. Можно делать раннер на конкретный список репозиториев. Первый создаётся через регистрационный токен на какой-то конкретный репозиторий, но потом, через UI GitLab можно добавить его ещё нескольким. Можно ещё тегами всё это разрулить.


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


Александр Швалов: У меня, к сожалению, не было такого опыта. Я знаю, что в серьезных организациях такое сплошь и рядом практикуется. Я могу лишь придумать такой способ: взять артефакт, сделать архив с релизной веткой репозитория, принести на флешке, там есть внутренний GitLab, сделать push в нужную ветку и сделать CI/CD как обычно, только в локальной сети.


Тимофей Ларкин: Вообще, я к таким историям скептически отношусь. Когда заказчик говорит, что у него невероятно секретно, гостайна (номера карт лояльности клиентов) и всё такое, то надо посмеяться и понять, что он врёт, и не работать с такими заказчиками. Но если работать очень надо (в конце концов, нам всем надо счета оплачивать и еду покупать), то есть вариант разместить раннер (управляющий бинарь; и пайплайны тоже будут где-то рядом запускаться) именно внутри контура заказчика.


Раннер умеет работать за NAT, умеет постучаться во внешний GitLab. Главное, чтобы сам GitLab не был за NAT, чтобы была нормальная доступность до GitLab. Поэтому да, раннер может изнутри контура заказчика сходить в ваш GitLab, стянуть код и делать сборку уже внутри инфраструктуры заказчика. И тогда чуть легче: артефакт сборки кладётся во внутренний репозиторий заказчика и оттуда уже деплоится всё хорошо. Не исключено, что там будет много сложностей. Наверняка, у заказчика свои самоподписные TLS-сертификаты, у него интернет недоступен на большинстве хостов (надо будет согласовать proxy, которая позволит раннеру ходить до вашего GitLab) и так далее.


Александр Швалов: Если proxy, NAT недопустимы, то в таком варианте остаётся паковать всё на своей стороне, собирать в инсталлятор, приходить к заказчику и обновлять приложение инсталлятором. Это уже другая задача, к CI/CD она вряд ли относится. Хотя можно настроить CI/CD, чтобы на выходе получался инсталлятор.


Тимофей Ларкин: Ну да, или держать все эти артефакты у себя в инфраструктуре, заказчику выдать публичный или приватный ключ, и просто ему на почту писать: Мы сделали новый этап работы, выложили новую версию, приходите забирайте.


А вообще я считаю, что такая ситуация возможна только в случае, если заказчик заплатил очень большие деньги или менеджер провалил переговоры. Потому что как в таком случае работать: постоянно ездить к заказчику? В принципе, если разработчики готовы ездить на территорию заказчика с флешками, это тоже вариант. Но для меня это фактически deal breaker, если заказчик предложит подобное.


Может нам как-то помочь CI/CD GitLab, если поставщик сам присылает собранные бинари в zip-архиве, и эти бинари необходимо распределить на нужное количество нод? Где это будет работать?


Александр Швалов:Речь о том, что есть в качестве исходного кода бинари в zip-архиве, и GitLab CI будет их каким-то образом распределять? В принципе, такое возможно. Почему нет? Можно это как-то сканировать, тестировать и деплоить, просто по SSH закидывать. В принципе, можно обойтись и без GitLab, одними скриптами.


Тимофей Ларкин: Можно какую-нибудь регулярную jobу запилить, которая, допустим, смотрит на папку, проверяет сумму у zip-архива, если обновилась, распаковывает, раскладывает его на внутренние nexus (приватный docker registry прим. редактора) в виде артефактов. Если надо, деплоит. Да, я думаю, GitLab может помочь в плане автоматизации этого процесса.


Узнать больше о курсе по CI/CD

Подробнее..

Перевод Создание современных процессов CICD для бессерверных приложений с Red Hat OpenShift Pipelines и Argo CD. Часть 2

27.01.2021 08:21:32 | Автор: admin


В первой части статьи я представил Tekton в качестве фреймворка для облачных пайплайнов CI/CD и Argo CD в качестве идеальной пары для GitOps в Red Hat OpenShift. Наша цель создать законченный процесс непрерывной интеграции и доставки, который начнется при коммите в репозитории GitHub и завершится, когда новое приложение будет развернуто в Dev, Staging и Prod средах.


В первой части мы использовали Tekton для реализации задач непрерывной интеграции (CI). Теперь мы завершим процесс CI/CD, реализовав задачи непрерывного развертывания (CD) с помощью Argo CD. Давайте посмотрим на схему на Рисунке 1, чтобы освежить в памяти процесс CI/CD.



Рис.1. Пример процесса CI/CD.


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


Во второй части мы воспользуемся возможностями Argo CD для полной автоматизации процесса развертывания приложения. Argo CD извлекает все изменения из файлов Kustomize, которые были отправлены в репозиторий развертывания пайплайном CI, и синхронизирует эти изменения в целевых неймспейсах. На последнем этапе нашей автоматизации мы напишем Tekton Trigger, который запустит весь процесс CI/CD.


Начало работы с Argo CD


Argo CD сейчас набирает популярность. Будучи первоклассным представителем экосистемы Kubernetes, он упрощает освоение GitOps, где команды используют декларативные описания конфигурации и инфраструктуры из Git в качестве единственного источника истины. Мы уже разработали задачи Tekton для нашего процесса CI/CD. Может ли Argo CD стать тем идеальным компонентом, которого сейчас не хватает в нашем процессе?


Установка Argo CD


Откройте веб-консоль OpenShift и перейдите в неймспейс cicd к нашему демонстрационному процессу. Используйте следующий скрипт, чтобы установить Argo CD Operator:


$ ./bootstrap-argo.sh cicd------------------------------Installing argo operatorRelease "argocd" does not exist. Installing it now.NAME: argocdLAST DEPLOYED: Thu Sep 10 18:37:23 2020NAMESPACE: defaultSTATUS: deployedREVISION: 1TEST SUITE: None

Как показано на Рисунке 2, вы должны теперь видеть новый Operator в неймспейсе cicd:



Рис. 2: Argo CD установлен в неймспейс проекта CICD.


Создание экземпляра Argo CD


Далее создадим экземпляр Argo CD. Этот экземпляр будет управлять всеми AppProjects и Applications, которые мы создали в неймспейсе cicd. Скрипты, приведенные ниже, создают следующее:


  • Экземпляр Argo CD в неймспейсе cicd.
  • AppProject под названием rh-developers.
  • Три приложения в AppProject rh-developers. Каждое приложение ссылается на репозиторий развертывания в ветке master. Приложения синхронизированы с папками development, staging и production соответственно.

Выполните следующее (не забудьте использовать собственный репозиторий quarkus-hello-world-deployment):


$ ./add-argo-apps.sh cicd rh-developers https://github.com/dsanchor/quarkus-hello-world-deployment.git master----------------------------------------------------------------------------------------------------------------Installing basic Argo CD server instanceargocd.argoproj.io/argocd createdAdding edit role to argocd-application-controller ServiceAccount in projects development, staging and productionrolebinding.rbac.authorization.k8s.io/edit-rh-developers-dev createdrolebinding.rbac.authorization.k8s.io/edit-rh-developers-staging createdrolebinding.rbac.authorization.k8s.io/edit-rh-developers-production createdCreating rh-developers AppProject in namespace cicdappproject.argoproj.io/rh-developers createdCreating Applications in namespace cicd in rh-developers AppProjectapplication.argoproj.io/quarkus-hello-world-development createdapplication.argoproj.io/quarkus-hello-world-staging createdapplication.argoproj.io/quarkus-hello-world-production created

Пропишите маршрут для Argo CD, который вам нужен для доступа к главной панели управления Argo CD:


$ oc get routes argocd-server -n cicd---------------------------------------NAME            HOST/PORT                                             PATH   SERVICES        PORT    TERMINATION            WILDCARDargocd-server   argocd-server-cicd.apps.ocp4.mydomain.com          argocd-server   https   passthrough/Redirect   None

Дождитесь, пока запустится сервер Argo CD, затем авторизуйтесь, используя свои данные OpenShift. И вуаля! Вы должны получить текущий статус ваших приложений, как показано на Рисунке 3.



Рис 3: Войдите в панель управления Argo CD для просмотра всех версий приложений и их соответствующих рабочих статусов.


Примечание: Вы можете заметить, что и приложение development, и приложение staging показывают свой статус как Synced, а приложение production OutOfSync. Первые два сконфигурированы с активированной функцией автосинхронизации, а для production мы используем ручную конфигурацию.


Запуск первой версии приложения


В следующих нескольких разделах мы проведем пару ревизий нашего приложения quarkus-hello-world на этапах development, staging и production цикла развертывания. Информацию о приложении Quarkus, которое мы используем для этого примера, вы можете прочитать в первой части этой статьи.


Первая версия приложения в среде development


Кликните на приложение quarkus-hello-world-development и увидите, что каждый объект в этой версии был синхронизирован, как показано на Рисунке 4.



Рисунок 4: Кликните на версию приложения, чтобы проверить его рабочий статус.


То, что все объекты синхронизированы, означает, что первая версия приложения была успешно развернута. Теперь получите маршруты, чтобы мы могли иметь доступ к сервису (обратите внимание, что маршруты для сервисов Knative автоматически создаются в неймспейсе knative-serving-ingress):


$ oc get routes -n knative-serving-ingress | grep development--------------------------------------------------------------route-e387d9ca-9f1b-4c15-9b83-7bea4d2d290c-313361326363   quarkus-hello-world-development.apps.ocp4.mydomain.com                   kourier    http2   edge/Allow    Noneroute-e387d9ca-9f1b-4c15-9b83-7bea4d2d290c-613962613835   r9ce9024-quarkus-hello-world-development.apps.ocp4.mydomain.com          kourier    http2   edge/Allow    None

Команда get routes должна выдать, как минимум, два маршрута: основной маршрут (quarkus-hello-world-development.apps.ocp4.mydomain.com) и один для новой версии, которую мы только что развернули (r9ce9024-quarkus-hello-world-development.apps.ocp4.mydomain.com). Обратите внимание, что основной маршрут может иметь за собой несколько версий, но, поскольку это наше первое развертывание, за ним закреплена только одна.


Протестируем оба маршрута и посмотрим на результаты. Если ни один под не работает, это происходит, потому что Knative уменьшает размер неактивных подов. Первый запрос может занять больше времени, чем обычно, если приходится создавать под заново.
Добавьте /hello, затем используйте curl, чтобы протестировать эндпоинт:


$ curl http://quarkus-hello-world-development.apps.ocp4.mydomain.com/hellohola dev! Yeap!$ curl http://r9ce9024-quarkus-hello-world-development.apps.ocp4.mydomain.com/hellohola dev! Yeap!

Теперь вы можете перейти в меню Serverless веб-консоли OpenShift, выбрать проект development и рассмотреть его, как показано на Рисунке 5.



Рис 5: Просмотрите проект development в меню OpenShift Serverless.


Первая версия приложения в среде staging


Снова зайдите в панель управления Argo CD и взгляните на приложение staging. Вы должны увидеть единственный файл ConfigMap, который показан на Рисунке 6.



Рис. 6: Посмотрим на приложение staging в панели управления Argo CD.


У нас есть только ConfigMap, потому что мы еще не создали kustomization.yaml. Возможно, вы помните из первой части статьи, что у нас есть файл под названием kustomization-REVISION.yaml. Чтобы синхронизировать изменения с файлом REVISION, нужно переименовать этот файл и отправить изменения в Git.
Перейдите в папку, где вы проверяли репозиторий развертывания и запустите:


$ git pull && \mv staging/kustomization-r9ce9024.yaml staging/kustomization.yaml && \git add  staging && git commit -m "Revision 9ce9024 is now active in staging" && \git push

Подождите пару минут, чтобы Argo CD синхронизировал все изменения. Если не терпится, можно нажать Sync, чтобы версия автоматически запустилась в staging, как показано на Рисунке 7.



Рис. 7: Argo CD синхронизирует и развертывает изменения, которые вы только что внесли.


Точно так же, как мы делали с приложением development, получите маршруты и проведите несколько тестов


$ oc get routes -n knative-serving-ingress | grep staging------------------------------------------------------------route-fd38a613-ea42-4809-af13-cd02503980bf-346238393864   quarkus-hello-world-staging.apps.ocp4.mydomain.com                       kourier    http2   edge/Allow    Noneroute-fd38a613-ea42-4809-af13-cd02503980bf-623763373761   r9ce9024-quarkus-hello-world-staging.ocp4.mydomain.com              kourier    http2   edge/Allow    None$ curl http://quarkus-hello-world-staging.apps.ocp4.mydomain.com/hellohola staging! Yeap!$ curl http://r9ce9024-quarkus-hello-world-staging.apps.ocp4.mydomain.com/hellohola staging! Yeap!

Первая версия приложения в среде production


Теперь мы переносим приложение в производственную среду, где ещё не настроена автоматическая синхронизация. Таким образом, все объекты нашего приложения сейчас в состоянии OutOfSync, как показано на Рисунке 8.



Рис. 8: Объекты в среде production должны быть синхронизированы вручную.


Чтобы новая версия приложения стала доступна для синхронизации, нам нужно одобрить это вручную. Проведите те же самые действия, что и для приложения в staging:


$ git pull && \mv production/kustomization-r9ce9024.yaml production/kustomization.yaml && \git add production && git commit -m "Revision 9ce9024 is now ready to be sync in production" && \git push

Через одну-две минуты вы увидите новые объекты, которые в данный момент помечены как OutOfSync, что видно на Рисунке 9.



Рис. 9: Добавьте новые объекты для текущего пересмотра и подтвердите действие на консоли Argo CD.


Если изменения совпадают с вашими ожиданиями, вы можете провести ручную синхронизацию, чтобы запустить новую версию в production. Нажмите кнопку Sync, и у вас, наконец, появится новая версия, которую можно тестировать. Этот этап показан на Рисунке 10.



Рис. 10: Нажмите кнопку Sync для синхронизации ваших изменений в текущей версии.


Теперь проведите несколько тестов production-маршрутов, используя ту же процедуру, которую вы использовали для циклов development и staging:


$ oc get routes -n knative-serving-ingress | grep production------------------------------------------------------------route-8c948175-70a8-4c1c-ae70-846aa3b2081f-643262313638   quarkus-hello-world-production.apps.ocp4.mydomain.com                    kourier    http2   edge/Allow    Noneroute-8c948175-70a8-4c1c-ae70-846aa3b2081f-663561353830   r9ce9024-quarkus-hello-world-production.apps.ocp4.mydomain.com           kourier    http2   edge/Allow    None$ curl http://quarkus-hello-world-production.apps.ocp4.mydomain.com/hellohola production! Yeap!$ curl http://r9ce9024-quarkus-hello-world-production.apps.ocp4.mydomain.com/hellohola production! Yeap!

Как показано на Рисунке 11, все приложения Argo CD сейчас синхронизированы.



Рис. 11: Все ваши объекты находятся на панели управления Argo CD.


Развертывание новой версии приложения


Давайте теперь посмотрим, что происходит при развертывании новой версии нашего приложения quarkus-hello-world. В этом случае мы просто снова запускаем пайплайн CI/CD с другим ID коммита. Заметьте: пока что мы продолжаем запускать пайплайн вручную. Мы установим вебхуки для пайплайнов в последнем разделе статьи.
Перейдите в репозиторий rh-developers-cicd и запустите пайплайн, используя следующие параметры:


$ cat tekton/pipelines/knative-pipeline-run.yaml | \  SOURCE_REPO=https://github.com/dsanchor/quarkus-hello-world.git \  COMMIT=c076ee940b1f1d9576b7af3250bbbd7114e82263 \  SHORT_COMMIT=c076ee9 \  DEPLOYMENT_REPO=https://github.com/dsanchor/quarkus-hello-world-deployment.git \  IMAGES_NS=cicd envsubst | \  oc create -f - -n cicd------------------------------------------------------------------------------------pipelinerun.tekton.dev/knative-pipeline-run-j5knc created

Если вы предпочитаете запускать пайплайн через tkn CLI, выполните следующее:


$ tkn pipeline start knative-pipeline -p application=quarkus-hello-world \  -p source-repo-url=https://github.com/dsanchor/quarkus-hello-world.git \  -p source-revision=c076ee940b1f1d9576b7af3250bbbd7114e82263 \  -p short-source-revision=c076ee9 \  -p deployment-repo-url=https://github.com/dsanchor/quarkus-hello-world-deployment.git \  -p deployment-revision=master \  -p dockerfile=./src/main/docker/Dockerfile.jvm \  -p image-registry=image-registry.openshift-image-registry.svc.cluster.local:5000 \  -p image-repository=cicd \  -w name=source,claimName=source-pvc \  -w name=maven-settings,config=maven \  -w name=knative-kustomize-base,config=knative-kustomize-base \  -w name=knative-kustomize-environment,config=knative-kustomize-environment \  -n cicd

Примечание: Выполнение пайплайна может занять до пяти минут. В это время предлагаю вам прочитать статью об ускорении сборки Maven в Tekton.
Когда пайплайн закочит работу, новый образ (quarkus-hello-world:c076ee940b1f1d9576b7af3250bbbd7114e82263) будет отправлен во внутренний registry OpenShift в неймспейсе cicd. Также новые Kustomization-файлы будут отправлены в репозиторий quarkus-hello-world-deployment.


Логи выполнения


Проверка логов пайплайна позволяет нам увидеть изменения, которые отправляются в Git. В особенности обратите внимание на записи задачи push-knative-manifest:


add 'development/kustomization.yaml'remove 'development/r9ce9024/configmap.yaml'remove 'development/r9ce9024/revision-patch.yaml'remove 'development/r9ce9024/routing-patch.yaml'add 'development/rc076ee9/configmap.yaml'add 'development/rc076ee9/revision-patch.yaml'add 'development/rc076ee9/routing-patch.yaml'add 'production/kustomization-rc076ee9.yaml'add 'production/rc076ee9/configmap.yaml'add 'production/rc076ee9/revision-patch.yaml'add 'production/rc076ee9/routing-patch.yaml'add 'staging/kustomization-rc076ee9.yaml'add 'staging/rc076ee9/configmap.yaml'add 'staging/rc076ee9/revision-patch.yaml'add 'staging/rc076ee9/routing-patch.yaml'

Подведем итог:


  • Новая версия доступна в development путем замены файла kustomization.yaml, который содержит ссылки на ресурсы новой версии. Заметьте, что в файле traffic-routing.yaml нет никаких изменений, так мы сохраняем все существующие правила маршрутов. (Например, мы можем сохранить все blue/green или canary правила маршрутов, сконфигурированные в предыдущей версии, если таковые были).
  • Мы только добавляем новый маршрут для новой версии, и мы убираем все ссылки на предыдущие версии. В основном маршруте все еще может быть ссылка на предыдущую версию, в таком случае эта версия может быть временно доступна через основной маршрут. После того, как версия становится не маршрутизируемой, Knative по истечению заранее установленного промежутка времени очистит ее как мусор. Использование Knative уменьшает трудозатраты на эксплуатацию и обслуживание и делает нас чуточку счастливее.
  • Мы также создаем необходимые файлы Kustomize для этой новой версии в средах staging и production, но на них еще нет ссылок в kustomization.yaml.

Вторая версия приложения в среде development


У нас есть новая версия сервиса Knative, но основной маршрут все еще ведет к предыдущему приложению, что показано на Рисунке 12.



Рис. 12: Основной маршрут указывает на предыдущую версию приложения.


Получите текущие маршруты для приложения, запущенного в среде development:


$ oc get routes -n knative-serving-ingress | grep development--------------------------------------------------------------route-e387d9ca-9f1b-4c15-9b83-7bea4d2d290c-313361326363   quarkus-hello-world-development.apps.ocp4.mydomain.com                   kourier    http2   edge/Allow    Noneroute-e387d9ca-9f1b-4c15-9b83-7bea4d2d290c-353136303164   rc076ee9-quarkus-hello-world-development.apps.ocp4.mydomain.com          kourier    http2   edge/Allow    None

Протестируйте оба, и вы заметите, что основной маршрут ведет к предыдущей версии:


$ curl http://quarkus-hello-world-development.apps.ocp4.mydomain.com/hellohola dev! Yeap!$ curl rc076ee9-quarkus-hello-world-development.apps.ocp4.mydomain.com/hellohola dev! Nice to see you back!

Если вы хотите направить часть трафика на новую версию по главному маршруту, просто измените traffic-routing.yaml. Зайдите в репозиторий quarkus-hello-world-deployment и выполните git pull. Затем переключитесь на папку development и отредактируйте файл traffic-routing.yaml.


Измените файл с этого:


- op: add  path: /spec/traffic  value:    - revisionName: quarkus-hello-world-r9ce9024      percent: 100

На этот:


- op: add  path: /spec/traffic  value:    - revisionName: quarkus-hello-world-r9ce9024      percent: 50    - revisionName: quarkus-hello-world-rc076ee9      percent: 50

И затем примените изменения:


$ git add development/traffic-routing.yaml && git commit -m "Splitted traffic between r9ce9024 %50 and rc076ee9 50" && \git push

Через две минуты Argo CD автоматически синхронизирует эти изменения, или вы можете запустить синхронизацию вручную, если хотите, чтобы изменения вступили в силу незамедлительно.


Если вы проверите основной маршрут, вы увидите, что он возвращает ответы от обеих версий:


$ watch -n1 curl http://quarkus-hello-world-production.apps.ocp4.mydomain.com/hello

Если вы хотите убедиться, что трафик не пойдет к какой-то старой версии приложения, просто уберите эту версию из файла traffic-routing.yaml. В итоге Knative ее очистит, что вы можете протестировать и самостоятельно.


Вторая версия приложения в среде staging


Мы еще не получили новую версию приложения в среде staging. Причина этого в том, что пайплайн CI еще не изменил файл kustomization.yaml. Вместо этого он только создал возможного кандидата:


kustomization-REVISION.yaml.

Давайте развернем эту новую версию (mv staging/kustomization-rc076ee9.yaml staging/kustomization.yaml). Мы пропишем тот же самый маршрут, что и в development, разделив трафик между двумя нашими текущими версиями:


$ git pull && \mv staging/kustomization-rc076ee9.yaml staging/kustomization.yaml && \cp development/traffic-routing.yaml staging/traffic-routing.yaml && \rm -rf staging/r9ce9024 && \git add  staging && git commit -m "Split traffic between r9ce9024 %50 and  rc076ee9 50%" && \git push

Заметьте, что мы также удалили папку более старой версии (rm -rf staging/r9ce9024). Пайплайн CI проделал это автоматически в development, но не в staging или production. Удаление предыдущей версии отличает development от двух других сред в демоверсии.
Окончательный результат приложения в staging будет таким же, как и в среде development, как показано на Рисунке 13.



Рис. 13: Приложения в development и staging синхронизированы.


Протестируем основной маршрут. Вы должны увидеть, что получаете ответы от обеих версий сервиса Knative:


$ watch -n1 curl http://quarkus-hello-world-staging.apps.ocp4.mydomain.com/hello

Вторая версия приложения в среде production


Как мы уже ранее отмечали, сценарий в production отличается от staging, потому что автоматическая синхронизация не предусмотрена для продакшена. Мы проделаем те же самые шаги, что и в staging, и посмотрим на результат:


$ git pull && \mv production/kustomization-rc076ee9.yaml production/kustomization.yaml && \cp staging/traffic-routing.yaml production/traffic-routing.yaml && \rm -rf production/r9ce9024 && \git add production && git commit -m "Split traffic between r9ce9024 %50 and rc076ee9 50%" && \git push

OutOfSync


Посмотрев на панель управления Argo CD, как на Рисунке 14, вы должны увидеть, что статус приложения quarkus-hello-world-production OutOfSync. Затронутый объект объект сервиса Knative.

Рис. 14: Объект сервиса Knative не синхронизирован.


Кликните на поле OutOfSync под quarkus-hello-world и проверьте вкладку DIFF, как показано на Рисунке 15.



Рис. 15: Используйте инструмент Diff, чтобы найти различия между версиями приложения.


Интерфейс на Рис. 15 показывает различия между действующим и желаемым манифестом, действующая версия представлена слева. Различия именно те, которые мы и предполагали, поэтому давайте синхронизируем их вручную и развернем новую версию и правила маршрутизации в production.
Проведя синхронизацию, протестируйте основной маршрут:


$ watch -n1 curl http://quarkus-hello-world-production.apps.ocp4.mydomain.com/hello

Откат к предыдущему состоянию


До сих пор вы смотрели, как развертывать новые версии приложения в каждой среде. А что если вы обнаружите непредвиденное поведение в последней версии приложения в production? Давайте используем Argo CD для отката к предыдущему состоянию приложения.
С Argo CD мы можем сделать откат к любой версии кода или приложения в истории нашего репозитория Git. Например, сделаем откат к предыдущей версии. Щелкните на History and Rollback на панели управления Argo CD, как показано на Рисунке 16.



Рис. 16: Использование функции History and Rollback, чтобы вернуться к предыдущей версии приложения.


Как только вы нашли ту версию, к которой хотите совершить откат, нажмите на меню в верхнем правом углу экрана и выберите там единственное действие: Rollback.



Рис. 17: Выберите нужную версию и нажмите Rollback.


Как показано на Рисунке 17, в результате приложение имеет текущий статус OutOfSync, но оно синхронизировано с версией, которую мы выбрали для отката. Проверьте, что откат сработал, проведя следующие тесты:


$ watch -n1 curl http://quarkus-hello-world-production.apps.ocp4.mydomain.com/hello

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


Примечание: Если у вас была активирована опция автосинхронизации для среды production, вам надо ее отключить перед проведением отката. Иначе все снова автоматически синхронизируется с последней версией.


Замыкаем круг: полностью автоматизированный CI/CD


До сих пор мы запускали пайплайн только вручную. Финальным этапом в нашем процессе мы настроим автоматизацию запуска пайплайна.


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


Перед началом сделайте форк репозитория исходного кода по адресу: https://github.com/dsanchor/quarkus-hello-world.git. Мы используем его для финального примера.


Добавление триггера Tekton


На стороне Tekton мы создадим три различных типа объектов, которые работают сообща:



В EventListener мы добавим два перехватчика:


  • Перехватчик GitHub добавляет простую проверку, основанную на общем токене.
  • Перехватчик CEL применяет базовую функцию для сокращения ID коммита, чтобы он стал доступен для пайплайна.

Первым шагом создайте secret со случайным токеном:


$ oc create secret generic webhook --from-literal=token=XXXXXXXXXXXXXX -n cicd

Затем создайте общие для разных приложений TriggerTemplate и TriggerBinding:


$ oc apply -f tekton/webhook/knative-pipeline-trigger.yaml -n cicd--------------------------------------------------------------------triggerbinding.triggers.tekton.dev/webhook-body-binding createdtriggertemplate.triggers.tekton.dev/knative-pipeline-template created

После этого создайте специфические для каждого приложения EventListener и TriggerBinding. Важно: используйте собственный репозиторий развертывания в DEPLOYMENT_REPO_URL:


$ cat tekton/webhook/app-custom-trigger.yaml | \  GITHUB_SECRET=webhook \  APPLICATION=quarkus-hello-world \  NS=cicd \  DEPLOYMENT_REPO_URL=https://github.com/dsanchor/quarkus-hello-world-deployment \  DEPLOYMENT_REPO_REVISION=master \  envsubst | oc apply -f - -n cicd-------------------------------------------------------------------------------------eventlistener.triggers.tekton.dev/quarkus-hello-world-listener createdtriggerbinding.triggers.tekton.dev/quarkus-hello-world-binding created

Сделайте expose для сервиса event-listener, который будет целевым эндпоинтом вашего вебхука в GitHub:


$ oc expose svc el-quarkus-hello-world-listener -n cicd

И получите маршрут:


$ oc get route el-quarkus-hello-world-listener -n cicd--------------------------------------------------------NAME                              HOST/PORT                                                               PATH   SERVICES                          PORT            TERMINATION   WILDCARDel-quarkus-hello-world-listener   el-quarkus-hello-world-listener-cicd.apps.ocp4.mydomain.com          el-quarkus-hello-world-listener   http-listener                 None

Настройка вебхука в GitHub


Теперь перейдите в репозиторий вашего приложения на GitHub. В пункте меню Settings выберите Webhooks -> Add Webhooks, как показано на Рисунке 18.



Рис. 18: Добавление вебхука в вашего приложения на GitHub проекта.


Добавьте маршрут в качестве URL-адреса полезной нагрузки, установите тип контента как JSON и, наконец, скопируйте содержание токена в раздел secret, как показано на Рисунке 19.



Рис. 19: Конфигурация вебхука.


Как только вы добавили эти финальные элементы, вы должны увидеть на экране единственный вебхук.


Проверим, что получилось


Я внесу простое изменение в класс GreetingResource. Вам нужно внести те же самые изменения в ваш Greeting Resource Test. В моем случае я меняю последнюю часть сообщения на Webhooks work.


После прохождения всех локальных тестов отправьте свои изменения в удаленный репозиторий:


$ git add src  && \git commit -m "Changed greeting message" && \git push

Пайплайн уже должен был запуститься. Если вы столкнетесь с ошибкой, вам стоит проверить event listener под в кластере, который мы создали для управления событиями для EventListener. Чтобы получить имя пода, выполните:


$ oc get pod -l eventlistener=quarkus-hello-world-listener -n cicd

Дождитесь завершения работы пайплайна. После этого у вас должна появиться новая версия сервиса Knative в окружении development. Вы можете использовать новинку: developer perspective в веб-консоли OpenShift для того, чтобы убедиться, что сервис Knative работает. Выберите проект development и проверьте его топологию, как показано на Рисунке 20.



Рис. 20: Используйте developer perspective OpenShift для того, чтобы убедиться в работе сервиса Knative.


Вы должны увидеть три работающие версии (хотя все они свёрнуты до минимума из-за неактивности). Две версии, которые мы с вами развернули за первые этапы этой статьи, лежат на основном маршруте, каждая из них берет на себя половину трафика. Последняя версия имеет свой маршрут, созданный нашим пайплайном. Давайте отправим на него запрос и посмотрим на результаты:


$ curl r1b644f0-quarkus-hello-world-development.apps.ocp4.mydomain.com/hellohola dev! Webhooks work!

Knative автоматически смасштабировал эту версию до одного пода, что показано на Рисунке 21.



Рис. 21: Knative провел автоматическое масштабирование последней версии приложения.


Заключение


Вторая часть статьи, посвященной введению в построение современных процессов CI/CD, познакомила вас с использованием Argo CD для реализации непрерывной доставки в бессерверном процессе CI/CD. Совмещение Tekton и GitOps при помощи Argo CD, становится все более популярным решением для полностью автоматического CI/CD.

Подробнее..

Перевод CICD обещания и реальность

24.02.2021 14:21:40 | Автор: admin


Мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. Вообще никогда. О нем все забыли. Пора это изменить.


Поучительная история


Один большой и страшный пиратский корабль наводил ужас на всю округу, хоть и подтекал немножко. После шторма или битвы пиратам нередко приходилось откачивать воду с нижних палуб.


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


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


Мораль истории такова: устраняйте не симптомы, а причину.


Что подводит нас к разговору о CI/CD?


CI/CD (непрерывная интеграция и доставка, или деплоймент) это часть нашей жизни. Мы ходим на конференции по CI/CD, пишем статьи о CI/CD, ведем блоги о CI/CD, указываем CI/CD на странице LinkedIn. Никто даже не спорит, надо оно нам или нет. Мы все одинаково обожаем CI/CD. Так ведь?


Вот только мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. О нем все забыли.


Нет, это замечательно, что мы так поднаторели в непрерывной интеграции за последние лет десять. Но этого же мало. Это даже не половина. Можно подумать, цель непрерывной интеграции наслаждаться своим красивым синтаксисом и логикой. Хотя это приятный бонус, кто же спорит. По факту же CI это просто подготовка к следующему этапу непрерывной доставке. Потому что вообще-то в этом вся суть.


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


Что это вообще такое CI/CD?


Отличный вопрос. Отвечу с удовольствием. CI/CD это процесс и методология, цель которой убедиться, что весь код, вливаемый в главную ветку, можно в любое время протестировать и задеплоить. Автоматически. После каждого дифа.


Цель конвейера CI/CD ускорить внедрение изменений в программах настолько, чтобы мы не успевали выпасть из контекста и забыть, что это были за изменения.


Если любой в вашей команде может отправить изменения в главную ветвь, точно зная, что через 15 минут они будут протестированы и развернуты в продакшене без человеческого вмешательства, наши поздравления! Вы используете CI/CD.


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


Гибельный водоворот разработки


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


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


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


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


Раз все имеющиеся разработчики заняты, нужно нанять много новых и потратить еще больше усилий на их координацию. Скоро вам понадобятся отдельные должности SRE, Ops, QA, билд-инженер, чтобы героически бороться с каждым симптомом по отдельности. Для этой оравы нужно будет больше менеджеров и так далее. Вуаля! Получаем огромную, дорогую и неповоротливую компанию.


Все становится еще медленнее, еще труднее, еще запутаннее. Нужно больше ресурсов, чтобы управлять этой навороченной системой и бороться с побочными эффектами, которые только усугубляют ситуацию. Нас затягивает в гибельный водоворот разработки. Есть и другой путь! Мы можем изначально делать все возможное, чтобы сократить интервал между написанием строки кода и ее полноценным деплойментом в продакшене. Это должно стать нашей навязчивой идеей. Давайте автоматизируем этот интервал, будем отслеживать его, потратим драгоценные ресурсы на его сокращение.


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


Каким должен быть интервал? В идеале 15 минут. Максимум час. Предсказуемость важна не меньше продолжительности, поэтому человек тут будет только мешать. Если сейчас вам требуется 15 дней, а не минут, не отчаивайтесь. Любые усилия по сокращению интервала обязательно окупятся. Любые!


Вижу, вы сомневаетесь. Моя команда, мол, такое не осилит, здесь вам не Facebook и не Google.


Вы идете сложным путем


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


Смотрите сами. Какой баг легче найти, понять, воспроизвести и исправить: баг в коде, который вы сами написали буквально только что, или баг в коде, который кто-то другой написал в прошлом году?


Как это вообще можно сравнивать? Пока код еще свеж в памяти, мы четко видим проблему и ее решение.


В процессе написания кода позаботьтесь о своем будущем я, которому через полчаса придется разбираться, получилось задуманное или нет. Итак, вы пишете код, отправляете его в главную ветку, ждете несколько минут и смотрите в продакшен. Все идет как надо? Или тут что-то не то?


В таком ритме разработчики обычно находят больше 80% всех багов сразу пока ничего еще не забылось и знаешь, на что смотреть. Если что-то пошло не так, можно тут же слепить еще один диф.


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


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


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


Задача номер 1 для технических руководителей в 2021 году


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


Создается впечатление, что это не техническая задача, а вопрос персонала, проблема управленцев. Руководители привыкли решать такие проблемы своими инструментами нанимая больше сотрудников.


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


В целом разработчики понимают ценность непрерывной доставки. Многие из них мечтают работать в таком режиме. Если у вас уже налажен CI/CD, это повысит вашу привлекательность как работодателя. Но главное ваша команда сможет эффективнее использовать существующий процесс разработки.


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


Вам бы понравилось, если бы ваши специалисты всегда вспоминали вас как человека, который изменил их мышление и подход к разработке, и были благодарны вам за то, что помогли им выйти на новый уровень? Все зависит от вас.


Не надо быть гением, чтобы раскрыть весь потенциал CI/CD. Честное слово. Надо просто приложить чуть больше усилий к тому, чтобы наладить этот процесс. Хорошие специалисты вырастают в хороших командах.


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


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


Сложно ли это? Еще как. Надеюсь, мне удалось вас убедить, что оно того стоит. Это изменит вашу жизнь. Это шаг к социотехническим системам будущего. Чем больше команд его сделают, тем лучше. А какой у вас план по CI/CD на 2021 год?


Узнать больше о CI/CD и получить практику создания пайплайнов можно на курсе Слёрма CI/CD на примере Gitlab CI.
Подробнее..

Зачем нужны непрерывная доставка и непрерывное развертывание?

01.06.2021 10:11:39 | Автор: admin

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

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

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

Определения

В данном материале будем пользоваться следующими тремя определениями М. Фаулера.

Непрерывная интеграция (Continuous Integration) когда продукт регулярно (несколько раз в день) собирается из исходного кода и для него запускается существенная часть автоматических тестов, например все модульные тесты. Если автоматические тесты работают долго, то их можно запускать реже, например раз в сутки. Стандартный подход для организации непрерывной интеграции это запустить TeamCity или Jenkins, которые будут загружать исходный код из системы контроля версий, собирать его и запускать тесты. Другие известные решения: Travis CI, GitLab, Space, GitHub, BitBucket.

Непрерывная доставка (Continuous Delivery) продукт всегда находится в собранном состоянии и готов к передаче в промышленную эксплуатацию, даже с учетом последних изменений, внесённых разработчиками в код. Скорее всего, непрерывная доставка будет реализована на основе тех же технологий, что и непрерывная интеграция. В этой статье на Хабре приводятся еще несколько подходящих открытых инструментов. В другой работе подробно рассматривается разница между реализацией конвейера сборки в облаке и на земле.

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

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

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

Две деревни

Чтобы разобраться в произношении названий, предлагаю заинтересованным почитать Ответы Mail.ru, а я далее буду пользоваться латиницей. О чем это я? Конечно, о двух захолустных деревнях Villarriba и Villabajo: обе деревни живут типичным сельским трудом производят программное обеспечение. Жители первой деревни вводят обновления своего продукта в промышленную эксплуатацию каждый день, ну, может быть, кроме пятниц (то есть практикуют непрерывную доставку или развертывание), а жители второй каждые две недели. На их примере предлагаю рассмотреть несколько параметров стандартного процесса изготовления и сопровождения программных продуктов. Это поможет лучше понять, в чем заключаются рассматриваемые подходы.

Скорость устранения ошибок

Жители Villabajo выкатывают изменения раз в две недели. За две недели они делают много новой функциональности, поэтому, когда они ошибаются в одной из новинок, им приходится либо 1) откатывать сразу все изменения и, если надо, выковыривать из версии дефектное изменение, собирать версию заново и ставить ее (впопыхах, естественно), либо 2) ковыряться сразу во всех изменениях, которые они выкатили, пытаться понять, какое из этих изменений привело к ошибкам, и отлаживать это в бою.

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

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

Но и здесь не все так просто: жители Villabajo не хотят ставить обновления часто не потому, что они такие злые, а потому, что у них плохо автоматизирован процесс публикации своего продукта. В результате они, в отличие от жителей Villarriba, страдают еще и от ошибок в продукте, порожденных неправильной установкой версии. На эту тему есть интересное исследование (стр. 53).

Затраты на установку новой версии

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

Тем не менее каждый житель Villabajo регулярно тратит по несколько часов, чтобы:

1) проверить версию на полноту включенных изменений (да, в полуавтоматическом режиме), включить в версию то, что забыли, и выкинуть то, что попало по ошибке, договориться с остальными жителями деревни и с заказчиком о том, что пришло время ставить обновление;

2) выполнить то, что нужно сделать до установки версии, например, запустить скрипты, отладить и починить их, потому что они не были полностью готовы к запуску в бою;

3) выполнить то, что нужно сделать во время установки версии, например, запустить скрипты, отладить и починить их, потому что они опять не были полностью готовы к запуску в бою;

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

Жители Villarriba готовы выкатывать изменения раз в день. Им приходится почти все время держать продукт готовым к введению в промышленную эксплуатацию с учетом самых последних обновлений. У них нет скриптов для выполнения перед установкой новой версии, во время и после нее. Они ведут разработку таким образом, чтобы можно было вводить новую функциональность постепенно, по одному небольшому контролируемому блоку за версию. Жителям Villabajo нет смысла так делать: у них же версии раз в две недели.

Что в итоге? Жители Villabajo каждые две недели тратят первую половину рабочего дня на то, чтобы установить версию, а вторую половину на просмотр YouTube (в лучшем случае чтение Хабра), потому что после стресса они не могут продуктивно работать (серьезно, см., например, вот эту публикацию, стр. 53). А жители Villarriba работают в обычном режиме, только иногда отвлекаются на то, чтобы откатить последние изменения с боевого сервера.

Рассматриваемый эффект уменьшение затрат на установку версии вполне очевиден и подтверждается реальными случаями. Например, непрерывная доставка помогла одной из команд Hewlett-Packard снизить общие затраты на разработку на 40%.

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

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

Включение и отключение новой функциональности

Жители Villabajo выкатывают изменения раз в две недели. Если их заказчик хочет какую-то функциональность, то он вместе с жителями Villabajo согласует дату, когда он увидит эту функциональность, и жители Villabajo готовят ее точно к сроку. Более того, в некотором смысле заказчик не может отказаться от запланированной функциональности: сначала этой функциональности нет на боевом сервере, потом есть день установки версии, а потом эта функциональность отлита в граните.

Чтобы откатить эту функциональность (либо из-за того, что жители Villabajo ошиблись, либо из-за того, что сам заказчик или другие взаимодействующие с продуктом Villabajo системы не готовы), надо установить предыдущую версию, удалить из новой версии оказавшуюся ненужной функциональность и установить эту исправленную новую версию. Особенно жители Villabajo унывают в таких случаях, когда новая версия успела создать данные, которые не могут быть обработаны старой версией: приходится чистить или переформатировать эти данные.

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

В отличие от жителей Villabajo, жители Villarriba тратятся на поддержание кода в адекватном состоянии и, возможно, на переключатели функциональности, но 1) им не приходится тратиться на откатывание оказавшихся ненужными изменений и на докатывание исправленных версий; 2) их заказчикам не нужно согласовывать миг, в который новая функциональность становится неотъемлемой частью системы.

Заказчики жителей Villarriba довольны. Это и неудивительно: положительное влияние такого подхода на отношения между заказчиком и исполнителем подтверждают научные исследования (стр. 67).

Продолжительность цикла разработка публикация корректировка

Жители Villabajo выкатывают изменения раз в две недели. В большинстве случаев они не имеют возможности проверить, как поведет себя новая функциональность на боевом сервере. В отличие от серьезных b2b-контор из столицы 6-й экономики мира у них есть много сред развертывания, и одна из них по своим параметрам почти совпадает с боевой.

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

Жители Villarriba могут позволить себе выдавать новую функциональность небольшими порциями, попадающими в боевую среду каждый день. После публикации версии (а они даже и не особенно следят за этим, для них публикация версии это просто обычный рабочий день) жители Villarriba смотрят, как их небольшие изменения отразились на системе и ее пользователях, и в зависимости от этого корректируют готовящуюся функциональность, по необходимости информируя своего заказчика об изменениях.

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

Пример: положительное влияние быстрой обратной связи отмечено в исследовании (стр. 65); там же сказано, что сами разработчики при этом лучше понимают, что они делают, и больше вовлечены в рассмотрение процессов предметной области. В другом исследовании (стр. 21) указывают на прямую корреляцию между тем, 1) насколько полно компании учитывают обратную связь от клиентов для исправления своих продуктов, 2) насколько просто заинтересованные сотрудники могут увидеть и осознать жизненный цикл продукта, 3) насколько сотрудники удовлетворены работой в компании и 4) насколько сильно сотрудники ассоциируют себя с компанией.

Функциональное и регрессионное тестирование

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

  • Очевидно, во время функционального тестирования проверяется, соответствует ли выполненная работа описанной и согласованной с клиентом постановке. В случае чего вносятся исправления.

  • В это время также может готовиться и приемочный сценарий для клиента.

  • Выявляются ошибки в тех местах, которые не покрыты автоматическими тестами.

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

  • Возможно, требуется и проведение нагрузочного тестирования.

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

Эту проблему решают переключатели функциональности. С их помощью можно держать внесенные изменения в спячке в тестовой среде (можно и в боевой, просто сейчас речь идет именно о тестовой среде) и включать их разом в тот момент, когда отдел собирается приступить к регрессионному тестированию. Во время тестирования разработчики вносят изменения, касающиеся других задач, например, для следующей версии. Эти изменения по умолчанию также пребывают в спячке и ждут, когда начнется тестирование следующей версии. Понятно, что переключатели функциональности помогают также и в приемочном тестировании.

Если вернуться к сюжету о двух деревнях, то скажем так: жители Villabajo заранее объединяют в одной тестовой среде все те и только те изменения, которые нужно протестировать за точно заданный временной промежуток, а жители Villarriba могут гибко менять объем тестируемых изменений и время проведения тестирования. Такое удобство досталось жителям Villarriba не бесплатно (они должны были по крайней мере внедрить переключатели функциональности), но ясно, что у нас тут вряд ли стоит искать преимущества, дающиеся без затрат.

Обобщение

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

Преимущества

  • Установка обновлений почти полностью автоматизирована, поэтому перестают появляться ошибки из-за неправильной установки обновления.

  • Установка обновлений почти полностью автоматизирована, поэтому вы ничего не тратите на установку новой версии.

  • Изменения быстрее интегрируются и проверяются на фоне в общем стабильной системы. Заинтересованные сотрудники быстрее получают обратную связь и лучше понимают свою роль и задачи в контексте продукта в целом (как системы). Поэтому становится меньше проблем на стыке зон ответственности; исчезают симптомы вида об этом должен позаботиться кто-то другой. Качество рождается на местах, а не обеспечивается отдельным процессом (подробнее об этом здесь, на стр. 22).

  • Установка обновлений почти полностью автоматизирована, поэтому сотрудники не выгорают во время установки новой версии.

  • Установка обновлений почти полностью автоматизирована, а изменения устанавливаются небольшими порциями, поэтому вы быстрее устраняете ошибки и восстанавливаете штатную работу продукта.

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

  • Установка обновлений почти полностью автоматизирована (как и весь цикл разработки), поэтому от идеи до появления ее реализации в промышленной эксплуатации проходит очень мало времени. Благодаря этому, заказчик и исполнитель могут легко проверять свои гипотезы о новой функциональности на практике, быстрее реализовывать полезную и удалять невостребованную функциональность.

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

  • Обновления устанавливаются автоматически, непрерывно и небольшими порциями, поэтому вы с заказчиком начинаете лучше понимать друг друга; исчезают проблемы вида сделали не то, что хотели.

  • Обновления устанавливаются автоматически и непрерывно. Заинтересованные сотрудники быстрее получают обратную связь и лучше понимают свою роль и задачи в контексте находящегося в промышленной эксплуатации продукта. Поэтому сотрудники больше вовлечены в предприятие (и в процесс создания продукта, и в его предметную область). Они сильнее ассоциируют себя как с продуктом, так и вообще с компанией.

Затраты

  • Чтобы наладить полуавтоматическую публикацию, вы должны купить и настроить соответствующее программное обеспечение. Если у вас уже есть непрерывная интеграция, то вы наверняка сможете переиспользовать ее инфраструктуру.

  • Чтобы наладить полуавтоматическую публикацию, вы должны провести организационные изменения. Например, если единственная команда владеет доступом к нужному серверу, нужно сделать так, чтобы к серверу имели доступ все заинтересованные сотрудники. Подробности в этой статье (стр. 53).

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

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

  • Чтобы вводить рассмотренные изменения, вам надо будет сломать консервативную корпоративную культуру у себя и у заказчика. Это, очевидно, означает, что между вами и заказчиком должно установиться доверие достаточно высокого уровня.

  • Чтобы иметь возможность публиковать обновления продукта несколько раз в день, вы должны поменять процессы таким образом, чтобы 1) установка новой версии не требовала отдельного согласования с заказчиком или чтобы 2) заказчик мог сам управлять включением и выключением новой функциональности.

Препятствия

Есть случаи, когда внедрить непрерывные доставку или развертывание почти невозможно.

  • Некоторые предметные области плохо поддерживают непрерывное развертывание (см. стр. 69 этого исследования), например, телекоммуникационное программное обеспечение и встраиваемое медицинское оборудование.

  • Еще проблемы могут возникнуть, когда речь идет о продукте большого объема, который не покрыт автоматическими тестами или который тяжело интегрируется с остальными системами.

Как у нас?

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

Заключение

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

Если будете вести свою зловещую пропаганду, можете ссылаться на отчет State of DevOps (стр. 13). В отчете утверждается, что в 2016 году успешные компании публиковали обновления намного чаще, чем остальные (экстремальные значения показали Amazon и Netflix несколько тысяч раз в день), и у них изменения быстрее проваливались по конвейеру от включения в исходный код до введения в промышленную эксплуатацию. Но только в таком случае лучше сразу сознаться, что прямой причинно-следственной связи здесь установить нельзя. Вероятнее всего, что непрерывное развертывание это только одно из свойств успешной компании.

Источники

  1. 1cloud.ru. Справочная: что такое Continuous Delivery (2019)

  2. Martin Fowler. ContinuousDelivery (2013)

  3. Jez Humble. The Case for Continuous Delivery (2014)

  4. B. Alanna, N. Forsgren, J. Humble et al. State of DevOps Report (2016)

  5. Chen, Lianping. Continuous Delivery: Huge Benefits, but Challenges Too (2015)

  6. Leppnen, M.; Mkinen, S.; Pagels, M.; Eloranta, V. P.; Itkonen, J.; Mntyl, M. V.; Mnnist, T. The Highways and Country Roads to Continuous Deployment (2015)

  7. A. Hkli, D. Taibi, K. Syst. Towards Cloud Native Continuous Delivery: An Industrial Experience Report (2018)

  8. Г. А. Минашин. Переключатели функциональности (feature toggles): виды, преимущества и работа с ними в .NET (2019)

  9. Манифест просвещенного программиста

  10. Как продать технические задачи бизнесу (2021)

  11. Где находятся Вилларибо и Виллабаджо?

Подробнее..

Фронт без релиз-инженера, или Как я перестал бояться и полюбил деплой

08.02.2021 14:10:06 | Автор: admin

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

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

  • Разделение ответственности в ряде случаев ответственность за деплой оказывается высокой.

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

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

Как это происходит у нас

В Учи.ру был создан собственный инструмент для выкатки сервисов и настройки стейджей под названием Шаман по сути кастомный интерфейс к HashiCorp Nomad. Несколько лет назад он помог уйти от исполнения скриптов на локальных машинах, автоматизировать процесс деплоя и позволил разработчикам создавать тестовые конфигурации максимально быстро. Об этом мои коллеги из команды инфраструктуры написали отдельную статью.

Немного истории

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

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

Да придет спаситель

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

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

И, кажется, коллеги со мной согласны:

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

Схема связи Шамана с кодом

На данный момент почти все наши GitHub-репозитории собираются при помощи GitHub Actions, в результате чего докер-образ пушится в общую приватную докер-репу. Этот workflow можно триггерить как автоматически (пуш в релизную ветку), так и руками, если хочется потестить какой-то сиюминутный фикс. Дальше Шаман подцепляет свежий образ и по кнопке раскатывает его на стейдж. Ну не красота, а?

И так как этот процесс находится в ведении разработчиков чуть более чем полностью, у нас есть возможность его упрощать. Меня, например, все-таки расстраивает необходимость сначала идти в GitHub, чтобы посмотреть статус билда, а потом в Шаман чтобы нажать на заветную зеленую кнопку для выкатки образа. После незначительной встряски коллег из инфраструктуры выяснилось, что последний предоставляет API, ручку которого можно дернуть из Github Actions с адресом для деплоя и идентификатором образа для деплоя. А это значит, что деплоить код можно полностью автоматически!

Когда что то идёт не так

Понятное дело, что после выкатки кода на прод надо убедится, что он ведёт себя так, как задумано. И тут у нас чуть хуже с автоматизацией, но тем не менее всё под контролем. Для мониторинга мы используем сервис Sentry, который нотифицирует как о новых индивидуальных ошибках, так и об изменениях общего фона. Ну и продуктовые дашборды с метриками никто не отменял. А Шаман, в свою очередь, быстро и непринужденно позволяет откатить бажную версию фронтового приложения в случае серьезных проблем.

Так нужно ли деплоить разработчику?

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

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

Ну и вопрос времени: деплоить самому куда быстрее, чем отдавать релиз выделенным инженерам. Но, естественно, с допущениями:

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

  • Стоит держать в голове, что мы работаем с in-house-решением со всеми вытекающими: оно может сломаться. Поэтому здесь нужно быть достаточно открытым и помогать коллегам чинить проблему, а не бранить решение.

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

Как происходит деплой в вашей компании? Считаете ли вы наш подход с одной кнопкой оптимальным или вам нравятся другие варианты выкатки новых сервисов и обновлений? Поделитесь мнением в комментариях.

Подробнее..

CICD монолита Авито от коммита до моржа

03.06.2021 12:19:11 | Автор: admin

Всем привет, меня зовут Александр Данковцев, я lead engineer команды Antimonolith. В этой статье я расскажу, как построен CI/CD монолита Авито. Речь пойдёт про нашу архитектуру стейджинга, pre-receive хуки, то, что из себя представляет сборка и деплой, как устроен прогон автотестов и какие проверки происходят на merge. А ещё рассмотрим after-merge actions.

Перед началом повествования введу пару понятий, которые будут использоваться дальше:

  • Релиз-кандидат версия кода, которому предстоит пройти процесс валидации тестов и деплой в продакшн при успехе.

  • Срез релиз-кандидата Git-ветка, созданная от мастера в процессе запуска сборки релиза.

Архитектура стейджинга Авито

Начнём со схемы архитектуры стейджинга. Это то, где вращается сам сайт Авито и компоненты, из которых он состоит:

Авито сайт, как и любой другой микросервис в стейджинг-окружении, деплоится встейджинговый Kubernetes-кластер. У нас есть отдельный namespace avito-site-tests, вкотором расположены ресурсы сайта: базы данных, баунсеры, сервис очередей, Sphinx, прочие репликации, всякие демоны. Это сделано для того, чтобы экономить ресурсы вкластере. Непосредственно каждая ветка сайта деплоится в собственный отдельный namespace, и все бэкенды натравливаются на ресурсы, которые расположены в отдельном неймспейсе. Особняком стоит Frontend Delivery Network (FDN), куда сгружается статика сайта.

Эта инфраструктура очень сложно деплоится: раскатить весь стейджинг одной кнопкой нельзя. Поэтому стейджинг поделен на Helm-релизы.

Отдельным релизом мы катим сами ресурсы, потому что это требуется очень редко. Ресурсы это база данных, Sphinx, Redis-ы, RabbitMQ. Также отдельно по срезу релиз-кандидатов или по требованию обновляются демоны монолита. На схеме это PGQ daemons, DataBus consumers и QaaS consumers. Мы вынесли их в отдельный деплой, чтобы перераскатка не пересоздавала базу данных, потому что база достаточно большая (около 10 Гб) и её пересоздание это сброс всех данных, созданных в процессе её работы, т. е. пропадут все созданные объявления и прочие ресурсы. Мы получим неконсистентное состояние с другими сервисами.

Деплой ресурсов стартует в 7 утра, когда все разработчики ещё спят, и к утру у нас есть готовая инфраструктура. Это позволяет нам тестировать в том числе и асинрохронное взаимодействие компонентов сайта. После раскатки ресурсов происходит пересоздание релиза кронов, демонов, консумеров.

Каждый сайт из второй колонки схемы деплоится по отдельности. Грубо говоря, это происходит по пушу в ветку: мы закоммитили, запушили, и ветка собралась в отдельный namespace. Отдельно деплоится статика, об этом расскажу позже.

Каждый бэкенд сайта Kubernetes Pod состоит из пяти контейнеров:

Nginx это точка входа плюс некоторая отдача статики.

Php-fpm сам бэкенд.

Envoy-core, который отвечает за прокси в сервисы, выполняет роль DNS resolve и keepalive. Например, мы можем стучаться по http://localhost:8888/service-item и попасть в service-item. Это всё нужно для большей производительности стейджинга.

Netramesh добавляет контекст в исходящие запросы: заголовок X-Source. Он также выполняет роль динамической подмены upstream-а сервисов по входящему заголовку X-Route. Формат такой: X-Router: src_host:src_port=dst_host:dst_port.

Navigator межкластерный маршрутизатор, который резолвит ClusterIP в набор PodIP во всех доступных дата-центрах.

Посмотрим на сетевой стек стейджинга. Когда мы запрашиваем произвольную ветку сайта, запрос проходит через фронденд nginx. В нашем случае это какой-то из подмножества avi-http, который отправляет запросы на Ingress. С Ingress мы попадаем в routing-gateway. Routing-gateway занимается подмешиванием заголовка X-Route и дальше прокидывает запрос в API-gateway. API-gateway балансит, куда отправить запрос: либо это будет Avito Site, либо какой-нибудь API-сomposition. API-сomposition это десктоп-сайт на Node.js или гошный сервис, либо любой другой сервис на любом другом языке.

Quality gates

Когда мы в общих чертах поняли, как выглядит стейджинг, рассмотрим quality gates, которые применяются для Avito Site.

Основные этапы прохождения коммита таковы:

  1. Гитовые pre-receive хуки.

  2. TeamCity: CI/CD прогоняет тесты, линтеры и так далее.

  3. Проверки на merge, флаги и обязательности.

  4. Действия после merge.

Давайте же покоммитим в монолит. Предположим, мы решили что-то поправить.

Pre-receive хуки

Pre-receive хуки помогают проверить, всё ли в порядке с коммитом до его пуша в репозиторий. Таких хуков у нас не очень много.

Мы проверяем, чтобы каждый коммит содержал имя задачи в Jira. Также есть элементарные проверки синтаксиса. Допустим, если где-то точку с запятой поставили не так, pre-receive хук скажет, что допущена синтаксическая ошибка. Мы проверяем и стиль, например, если пропущен нужный пробел между операторами, линтер сообщит об этом и не даст запушить ветку.

Плюс есть проверка на то, что коммит наш доменный, он принадлежит Авито, а не какой-то левый.

Что происходит в TeamCity

Вот максимально упрощённый граф зависимостей нашего CI/CD, я собрал основные этапы прохождения:

У нас есть всякие схема-чеки, DI-чеки, юнит-тесты, но лишь вершина айсберга. Из всей схемы я рассмотрю самый основной и сложный процесс прохождение end-to-end тестов от сборки Docker до прогона тестов.

Сборка

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

В сборке образа мы используем паттерн build-образ и push-образ. Build-образ большой и тяжёлый, с кучей зависимостей, сишных библиотек и прочих утилит, которые нужны, чтобы собирать непосредственно код. Для рантайма же этих зависимостей не должно быть. То есть унас собирается некоторый артефакт на этапе build code, после этого сбилженная статика загружается в Ceph. А остальная часть собранного кода запекается в Docker-образ и позже пушится.

Вот как происходит build code:

  1. Установка composer-зависимостей.

  2. Кодогенерация, например, генерация client-shop.

  3. Сборка DI, у нас используется Symfony.

  4. Сборка фронденда. Собирается npm, собирается Twig в кэши.

  5. Деплой хранимых процедур. Мы получаем свободного юзера, назначаем ему схему, search pass, и накатываем туда хранимки.

  6. Сборка словарей файловое представление справочных данных из базы или сервисов.

  7. Если всё прошло успешно, последний этап сборка артефактов, то есть генерация app.toml, swagger, rev.txt. Rev.txt это идентификатор сборки, окружение, в котором она собиралась, и прочая отладочная информация.

Деплой

Когда образ собрался и запушился, приходит следующая TeamCity сборка деплой.

Процесс следующий:

  1. Деплой в Kubernetes-кластер.

  2. Валидация доступности хоста: делается curl с небольшим прогрессирующим шагом, пока хост не станет отдавать код 200. Helm предоставляет информацию о том, что он успешно раскатился, проходят health-чеки и так далее.

  3. Регистрация хоста в routing-gateway.

  4. Автоматическая отбивка в Slack, о том, что хост собрался.

Автотесты

Хост собрался, самое время запускать end-to-end тесты. Если говорить простым языком, у нас сначала отрабатывает сборка Build E2E. В отдельный архив собирается папка с тестами и пушится в Artifactory. От E2E-тестов идёт много связей, я приводил их на первой картинке проTeamCity.

Для простоты рассмотрим одну из них E2E Test Suite. В этом билде настроено, какой тип тестов запускать, допустим, web или api, или заданы какие-то дополнительные параметры, например, относящиеся к конкретному юниту Авито. Этот билд общается с сервисом параллельного запуска автотестов: посылает ему задачу, сервис её исполняет и получает ответ.

Если копнуть немного глубже, то билд, прогоняющий тесты, представляет собой TeamCity meta runner, который через Docker запускает небольшое приложение, где реализован клишный parallel-client. Parallel-client делает запрос в parallel manager и передаёт ему все метаданные сборки: какие тесты к какому юниту относятся, какой артефакт был запушен в Artifactory. Parallel manager, получив результат, перекладывает всё в очередь и отвечает клиенту, что всё окей, я принял результат. После этого клиент начинает периодически поллить parallel manager на информацию о том, прошли тесты или нет.

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

Тесты ходят в Selenium, который ходит по сайту через Firefox, Chrome или любой другой браузер. Тесты также пользуются файловой системой (fs-qa), куда сохраняют скриншоты, html-странички и прочее. На результат выполнения смотрит воркер: для успеха код ответа 0, для провала 1.

После этого parallel worker пушит каждый выполненный кусочек задачи в отдельную очередь результаты выполнения тестов. Эту очередь слушает parallel manager. Когда менеджер получает результаты, он отгружает их в tests reporters backend, где хранятся отчёты о том, что такой-то тест столько-то выполнялся и прочая информация.

Parallel client через cli-команду запрашивает у test reporter backend финальную информацию отом, что все тесты пройдены. В ней отмечено, сколько тестов прошли, например, 150 из 170. На основе этой информации билд становится зелёным или красным. Также после получения этой информации в TeamCity создаётся артефакт со ссылкой на frontend test reporter. Мы можем зайти в него из TeamCity и визуально посмотреть полную отчётность о том, какие тесты прошли и сколько они выполнялись.

Вот как весь процесс выглядит схематически:

Каждый Е2Е-тест создаёт свою коллекцию тестов, а каждая коллекция тестов создаёт свои репорты, и их довольно много. На прогоне ветки для сайта у нас получается семь Е2Е-сьютов, а для релиза их порядка 50 штук. Когда все отчёты собрались и пришли отбивки в stash, мы можем зайти в stash и замерджить ветку.

Проверки на merge

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

Merge-плагин анализирует diff, то, какие файлы были изменены, и выставляет флаги для текущего pull request. Если в pull request были изменения PHP-файлов, он ставит backend changes, если были изменения JS или CSS frontend changes. Маркируются и случаи, когда произошли изменения в папке с Е2Е-тестами, например, buyer test changes. В итоге работы плагина у pull request появляются флаги, что в нём потрогали: frontend, backend и тесты байеров.

Наименование флага

Значение

Условие

Backend changes

Yes

*.php

Frontend changes

No

*.css, *.js

Buyer E2E changes

No

tests/e2e/BuyerTests/*

DataBase changes

Yes

*.sql

Также у нас есть карта всех билдов, которые мы хотим валидировать на pull request Avito Site. Но мы не хотим, чтобы каждое изменение в read.me порождало требование пройти 30проверок. Мы хотим, чтобы если потрогали какой-нибудь текстовый файлик, было наличие только одного апрува. Это достигается тем, что каждая проверка маркируется списком флажков, на которые она должна срабатывать.

Наименование линтера

Список флажков

UnitTests

Backend changes

FrontendCI

Frontend changes

DockerBuild

Backend changes, Frontend changes, Database changes

BuyerE2E Suite

Buyer E2E changes

Например, для "BuyerE2E Suite" проверка прогоняется в том случае, если на pull request был выставлен флаг "Buyer E2E changes". Если мы не трогали папку с байерами, то проверки не будут обязательными, на pull request не будет требоваться, что они должны быть зелёными. Если потрогали SQL-ки, значит, обязательно должны пройти интеграционные тесты на базе, и так далее.

Действия после merge

Когда все тесты прошли, все условия соблюдены, все нужные галочки стоят, мы наконец-то можем слить ветку в мастер. Но здесь всё не останавливается. После этого у нас срабатывает механика after-merge.

Её реализует плагин в нашем stash, который слушает изменения на merge и триггерит соответствующие сборки в TeamCity. Прежде всего, он делает удаление хоста, что экономит нам ресурсы: Kubernetes не резиновый. Ceph тоже не резиновый, поэтому после мерджа происходит очистка статики. И в конце плагин снимает регистрацию с routing-gateway.

Теперь всё, мы в мастере.

А что с релизами?

В статье я не стал рассматривать релизы Авито. Они, в принципе, очень похожи на описанный выше процесс. В релизах просто происходит не pull request в мастер, а срез ветки. Востальном смысл тот же: сборка сайта, прогоны Е2Е-тестов, просто их больше, а вместо проверки в stash на merge-check валидация релиз-инженерами.

Подробнее..

Перевод CICD-конвейеры с охватом нескольких кластеров OpenShift

29.04.2021 16:13:12 | Автор: admin

Традиционно конвейеры CI/CD строились поверх физических серверов и виртуальных машин. Контейнерные платформы, вроде Kubernetes и OpenShift, появились на этой сцене гораздо позже. Однако по мере того, как все больше и больше рабочих нагрузок переводится на платформу OpenShift, туда же движутся и конвейеры CI/CD, а конвейерные задания все чаще выполняются внутри контейнеров, работающих на кластере.

Этот пост представляет собой перевод блога нашего друга Алеса Носика, автора блога имени себя ("Helping you navigate the world of Kubernetes"). Девиз Алеса: "Software developer and architect passionate about new technologies, open-source and the DevOps culture. Making the world a better place with software".

Вы можете задать любой вопрос после прочтения Алесу в комментариях. Ну и куда без этого Алес хочет подарить за самые каверзные вопросы набор пешего туриста с картой маршрутов от Red Hat. И шляпу.

В реальном мире компании не ограничиваются одним-единственным кластером OpenShift, а имеют их сразу несколько. Почему? Чтобы запускать рабочие нагрузки как в различных публичных облаках, так и на своих собственных ИТ-мощностях. Либо если организация хранит верность какому-то одному поставщику платформ для того, чтобы эффективно работать в различных регионах мира. А иногда необходимо иметь несколько кластеров и в одном регионе, например, при наличии нескольких зон безопасности, в каждой из которых должен быть свой кластер.

Как видим, у организаций есть масса причин иметь нескольких кластеров OpenShift. Соответственно, конвейеры CI/CD должны уметь работать в таких мультикластерных системах, и ниже мы расскажем, как проектировать такие конвейеры.

CI/CD-конвейер Jenkins

Jenkins это настоящая легенда в мире CI/CD. А ведь когда-то давно он назывался Hudson, впрочем, это совсем уже древняя история. Вернемся к нашей теме и зададимся вопросом, как построить конвейер Jenkins, охватывающий сразу несколько кластеров OpenShift? При проектировании такого конвейера очень важно предусмотреть единую информационную панель, где отображались бы результаты выполнения всех заданий, задействованных в этом конвейере. Если немного подумать, то для этого надо иметь некий главный Jenkins (назовем его мастер-Jenkins), который будет связан с каждым кластером OpenShift. При выполнении конвейера мастер-Jenkins сможет запускать отдельные задания на любом из подключенных кластеров, а журналы вывода заданий будут собираться отправляться на этот мастер-Jenkins, как обычно. Если у нас есть три кластера OpenShift (Dev, Test и Prod), то схема будет выглядеть следующим образом:

Для подключения Jenkins к OpenShift есть замечательный Kubernetes-plugin, с помощью которого мастер-Jenkins сможет создавать эфемерные worker-ы на кластере. Каждому кластеру можно присвоить свою метку узла, чтобы иметь возможность запускать каждый этап конвейера на разных кластерах, просто задавая соответствующую метку. Вот как выглядит простое определение такого конвейера:

stage ('Build') {  node ("dev") {    // running on dev cluster  }}stage ('Test') {  node ("test") {    // running on test cluster  }}stage ('Prod') {  node ("prod") {    // running on prod cluster  }}

В OpenShift есть специальный шаблон для Jenkins, который можно найти в проекте openshift. Этот шаблон позволяет создать мастер-Jenkins, который преднастроен для запуска worker-podов на одном кластере. А дальше придется приложить определенные усилия, чтобы подключить этот мастер-Jenkins к другим кластерам OpenShift, и вся хитрость здесь заключается в настройке сети. Jenkins-овский worker-pod после запуска подключается к мастер-Jenkins. Поэтому нам надо, чтобы мастер-Jenkins был доступен для worker-ов, работающих на любом из наших кластеров OpenShift.

Кроме того, стоит обсудить безопасность. Если мастер-Jenkins может запускать worker-овские pod-ы на OpenShift, то значит он может запускать на этих worker-ах произвольный код. Кластер OpenShift не имеет возможности контролировать, какой код запустит Jenkins-овский worker. Определения заданий управляется Jenkins, поэтому только Jenkins-овские средства контроля доступа решают, можно ли выполнять то или иное задание на том или ином кластере.

Kubernetes-нативный конвейер Tekton

Теперь посмотрим, как организовать мультикластерный конвейер CI/CDВ с помощью Tekton. В отличие от Jenkins, Tekton это Kubernetes-нативное решение: он реализован на основе строительных блоков Kubernetes и тесно интегрирован с Kubernetes. Естественная граница Tekton это кластер. И как тут построить конвейер, который будет охватывать сразу несколько кластеров OpenShift?

Для этого можно скомпоновать схему из несколько конвейеров Tekton. Чтобы объединить несколько конвейеров в один, мы создадим задачу execute-remote-pipeline, которая будет запускать Tekton-конвейер, расположенный на удаленном кластере OpenShift. При выполнении удаленного конвейера эта задача будет подхватывать его вывод. Теперь с помощью этой задачи мы можем объединять несколько конвейеров Tekton на разных кластерах OpenShift и запускать их как один конвейер. Например, на диаграмме ниже показана композиция из трех конвейеров, где каждый из них расположен на своем кластере OpenShift (Dev, Test и Prod):

Выполнение этого конвейера начинается на кластере Dev. Конвейер Dev запустит конвейер Test, который, в свою очередь, запустит конвейер Prod. Объединенные логи можно отследить к окне терминала:

$ tkn pipeline start dev --showlogPipelinerun started: dev-run-bd5fsWaiting for logs to be available...[execute-remote-pipeline : execute-remote-pipeline-step] Logged into "https://api.cluster-affc.sandbox1480.opentlc.com:6443" as "system:serviceaccount:test-pipeline:pipeline-starter" using the token provided.[execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] You have one project on this server: "test-pipeline"[execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] Using project "test-pipeline".[execute-remote-pipeline : execute-remote-pipeline-step] Welcome! See 'oc help' to get started.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Logged into "https://api.cluster-affc.sandbox1480.opentlc.com:6443" as "system:serviceaccount:prod-pipeline:pipeline-starter" using the token provided.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] You have one project on this server: "prod-pipeline"[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Using project "prod-pipeline".[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] Welcome! See 'oc help' to get started.[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step] [prod : prod-step] Running on prod cluster[execute-remote-pipeline : execute-remote-pipeline-step] [execute-remote-pipeline : execute-remote-pipeline-step][execute-remote-pipeline : execute-remote-pipeline-step]

Обратите внимание, что в этом примере показано каскадное выполнение конвейеров Tekton. Есть и способ компоновки последовательное выполнение нескольких удаленных конвейеров.

Прежде чем переходить к заключению, кратко обсудим компоновку конвейеров с точки зрения безопасности. Kubernetes-нативность Tekton означает, что все управление доступом в нем осуществляется через RBAC. Поэтому, чтобы задача, запущенная на локальном кластере (допустим, на кластере Test на нашей схеме), могла запустить конвейер на удаленном кластере (Prod), у нее должны быть соответствующие разрешения, которые задаются на удаленном кластере (Prod). Таким образом, удаленный кластер, работающий в среде более высоко уровня (Prod), может ограничивать доступ для задач, работающие в среде более низкого уровня (Test). Например, Prod может разрешать Test-у запускать только штатные продакшн-конвейеры, поэтому Test не сможет создавать новые конвейеры в кластере Prod.

Заключение

Итак, мы показали, как в Jenkins и Tekton создавать конвейеры CI/CD, охватывающие сразу несколько кластеров OpenShift, обсудив некоторые аспекты их проектирования, безопасности и реализации.

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

Автор: Ales Nosek

13 мая Алес расскажет про Apache Airflow на OpenShift, и там тоже можно будет задавать вопросы, получать подарки и все такое.

Подробнее..

Ansible-vault decrypt обходимся без Ansible

25.04.2021 02:04:46 | Автор: admin

Исходные данные

Дано:

  • конвейер CI/CD, реализованный, к примеру, в GitLab. Для корректной работы ему требуются, как это очень часто бывает, некие секреты - API-токены, пары логи/пароль, приватные SSH-ключи - да всё, о чём только можно подумать;

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

Требуется консольная утилита, которая:

  • занимает минимум места;

  • умеет расшифровывать секреты, зашифрованные ansible-vault;

  • не требует никаких внешних зависимостей;

  • умеет читать ключ из файла.

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

На всякий случай сразу напоминаю, что по действующему законодательству разработка средств криптографической защиты информации в РФ - лицензируемая деятельность. Иначе говоря, без наличия лицензии вы не можете просто так взять и продавать получившееся решение.

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

Начнём сначала

Итак, предположим, что у нас на Linux-хосте с CentOS 7 уже установлен Ansible, к примеру, версии 2.9 для Python версии 3.6. Установлен, конечно же, с помощью virtualenv в каталог "/opt/ansible". Дальше для целей удовлетворения чистого научного любопытства возьмём какой-нибудь YaML-файл, и зашифруем его с помощью утилиты ansible-vault:

ansible-vault encrypt vaulted.yml --vault-password-file=.password

Этот вызов, как можно догадаться, зашифрует файл vaulted.yml с помощью пароля, который хранится в файле .password.

Итак, что получается после зашифровывания файла с помощью утилиты ansible-vault? На первый взгляд - белиберда какая-то, поэтому спрячу её под спойлер:

Содержимое файла vaulted.yml
$ANSIBLE_VAULT;1.1;AES256613735363539633137393665366436613138616632663731303737306666343433373565363336643365393033623439356364663537353365386464623836640a356464633264626330383232353362636131353736383936656639623035303230613764323339313061613039666333383035656663376465393837636665300a633732313730626265636538363339383237306264633830653665343639303538636331373138663935666436613235366336663438376231303639666133633739623436303438623463323636336332643666663064393731363034623038653861373536643136393431636437346337323833333165386534353432386663343465333836643131643237313262386634396534383166303565306264303162383833643765613936373632626136663738363462626665366131646631663834316262663162353532366664386330323139643266636562653639306238653162316563613934323836303536613532623864303839313038336232616134626433353166383837643165643439363835643731316238316439633039

Ну а как именно эта белиберда работает "под капотом" - давайте разбираться.

Открываем файл /opt/ansible/lib/python3.6/site-packages/ansible/parsing/vault/__init__.py, и в коде метода encrypt класса VaultLib видим следующий вызов:

VaultLib.encrypt
 ... b_ciphertext = this_cipher.encrypt(b_plaintext, secret) ...

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

Смотрим в его метод encrypt:

VaultAES256.encrypt
@classmethoddef encrypt(cls, b_plaintext, secret):    if secret is None:        raise AnsibleVaultError('The secret passed to encrypt() was None')    b_salt = os.urandom(32)    b_password = secret.bytes    b_key1, b_key2, b_iv = cls._gen_key_initctr(b_password, b_salt)    if HAS_CRYPTOGRAPHY:        b_hmac, b_ciphertext = cls._encrypt_cryptography(b_plaintext, b_key1, b_key2, b_iv)    elif HAS_PYCRYPTO:        b_hmac, b_ciphertext = cls._encrypt_pycrypto(b_plaintext, b_key1, b_key2, b_iv)    else:        raise AnsibleError(NEED_CRYPTO_LIBRARY + '(Detected in encrypt)')    b_vaulttext = b'\n'.join([hexlify(b_salt), b_hmac, b_ciphertext])    # Unnecessary but getting rid of it is a backwards incompatible vault    # format change    b_vaulttext = hexlify(b_vaulttext)    return b_vaulttext

То есть перво-наперво генерируется "соль" длиной 32 байта. Затем из побайтного представления пароля и "соли" вызовом _gen_key_initctr генерируется пара ключей (b_key1, b_key2) и вектор инициализации (b_iv).

Генерация ключей

Что же происходит в _gen_key_initctr?

_gen_key_initctr:
@classmethoddef _gen_key_initctr(cls, b_password, b_salt):    # 16 for AES 128, 32 for AES256    key_length = 32    if HAS_CRYPTOGRAPHY:        # AES is a 128-bit block cipher, so IVs and counter nonces are 16 bytes        iv_length = algorithms.AES.block_size // 8        b_derivedkey = cls._create_key_cryptography(b_password, b_salt, key_length, iv_length)        b_iv = b_derivedkey[(key_length * 2):(key_length * 2) + iv_length]    elif HAS_PYCRYPTO:        # match the size used for counter.new to avoid extra work        iv_length = 16        b_derivedkey = cls._create_key_pycrypto(b_password, b_salt, key_length, iv_length)        b_iv = hexlify(b_derivedkey[(key_length * 2):(key_length * 2) + iv_length])    else:        raise AnsibleError(NEED_CRYPTO_LIBRARY + '(Detected in initctr)')    b_key1 = b_derivedkey[:key_length]    b_key2 = b_derivedkey[key_length:(key_length * 2)]    return b_key1, b_key2, b_iv

Если по сути, то внутри этого метода вызов _create_key_cryptography на основе пароля, "соли", длины ключа и длины вектора инициализации генерирует некий производный ключ (строка 10 приведённого фрагмента). Далее этот производный ключ разбивается на части, и получаются те самые b_key1, b_key2 и b_iv.

Следуем по кроличьей норе дальше. Что внутри _create_key_cryptography?

_create_key_cryptography:
@staticmethoddef _create_key_cryptography(b_password, b_salt, key_length, iv_length):    kdf = PBKDF2HMAC(        algorithm=hashes.SHA256(),        length=2 * key_length + iv_length,        salt=b_salt,        iterations=10000,        backend=CRYPTOGRAPHY_BACKEND)    b_derivedkey = kdf.derive(b_password)    return b_derivedkey

Ничего особенного. Если оставить в стороне всю мишуру, то в итоге вызывается функция библиотеки OpenSSL под названием PBKDF2HMAC с нужными параметрами. Можете, кстати, самолично в этом убедиться, открыв файл /opt/ansible/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py.

Кстати, длина производного ключа, как видите, специально выбирается таким образом, чтобы хватило и на b_key1, и на b_key2, и на b_iv.

Собственно шифрование

Движемся дальше. Здесь нас встречает вызов _encrypt_cryptography с параметрами в виде открытого текста, обоих ключей и вектора инициализации:

_encrypt_cryptography
@staticmethoddef _encrypt_cryptography(b_plaintext, b_key1, b_key2, b_iv):    cipher = C_Cipher(algorithms.AES(b_key1), modes.CTR(b_iv), CRYPTOGRAPHY_BACKEND)    encryptor = cipher.encryptor()    padder = padding.PKCS7(algorithms.AES.block_size).padder()    b_ciphertext = encryptor.update(padder.update(b_plaintext) + padder.finalize())    b_ciphertext += encryptor.finalize()    # COMBINE SALT, DIGEST AND DATA    hmac = HMAC(b_key2, hashes.SHA256(), CRYPTOGRAPHY_BACKEND)    hmac.update(b_ciphertext)    b_hmac = hmac.finalize()    return to_bytes(hexlify(b_hmac), errors='surrogate_or_strict'), hexlify(b_ciphertext)

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

Полученные в итоге байты подписи и шифртекста преобразуются в строки своих шестнадцатеричных представлений через hexlify. (см. строка 14 фрагмента выше)

Окончательное оформление файла

Возвращаемся к строкам 16-20 фрагмента VaultAES256.encrypt: три строки, содержащие "соль", подпись и шифртекст, склеиваются вместе, после чего снова преобразуются в шестнадцатеричное представление (комментарий прямо подсказывает, что это - для обратной совместимости).

Дальше дописывается заголовок (помните, тот самый - $ANSIBLE_VAULT;1.1;AES256), ну и, в общем-то, всё.

Обратный процесс

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

Понятно, что Python нам не подходит, иначе можно было и огород не городить: ansible-vault одинаково хорошо работает в обе стороны. С другой стороны, никто не мешает на базе библиотек Ansible написать что-либо своё - в качестве разминки перед "подходом к снаряду" я так и сделал, и о результате напишу отдельную статью.

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

Итак, нам понадобятся: FreePascal версии 3.0.4 (эта версия в виде готовых пакетов - самая свежая, нормально устанавливающаяся в CentOS 7), и библиотека DCPCrypt версии 2.1 (на GitHub). Интересно, что прямо вместе с компилятором (fpc) и обширным набором библиотек в rpm-пакете поставляется консольная среда разработки fp.

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

Часть кода, относящуюся к генерированию производного ключа (реализацию той самой функции PBKDF2), я нашёл в интернете, и поместил в отдельный модуль под названием "kdf".

Вот этот модуль собственной персоной:

kdf.pas
{$MODE OBJFPC}// ALL CREDITS FOR THIS CODE TO https://keit.co/p/dcpcrypt-hmac-rfc2104/unit kdf;interfaceuses dcpcrypt2,math;function PBKDF2(pass, salt: ansistring; count, kLen: Integer; hash: TDCP_hashclass): ansistring;function CalcHMAC(message, key: string; hash: TDCP_hashclass): string;implementationfunction RPad(x: string; c: Char; s: Integer): string;var  i: Integer;begin  Result := x;  if Length(x) < s then    for i := 1 to s-Length(x) do      Result := Result + c;end;function XorBlock(s, x: ansistring): ansistring; inline;var  i: Integer;begin  SetLength(Result, Length(s));  for i := 1 to Length(s) do    Result[i] := Char(Byte(s[i]) xor Byte(x[i]));end;function CalcDigest(text: string; dig: TDCP_hashclass): string;var  x: TDCP_hash;begin  x := dig.Create(nil);  try    x.Init;    x.UpdateStr(text);    SetLength(Result, x.GetHashSize div 8);    x.Final(Result[1]);  finally    x.Free;  end;end;function CalcHMAC(message, key: string; hash: TDCP_hashclass): string;const  blocksize = 64;begin  // Definition RFC 2104  if Length(key) > blocksize then    key := CalcDigest(key, hash);  key := RPad(key, #0, blocksize);  Result := CalcDigest(XorBlock(key, RPad('', #$36, blocksize)) + message, hash);  Result := CalcDigest(XorBlock(key, RPad('', #$5c, blocksize)) + result, hash);end;function PBKDF1(pass, salt: ansistring; count: Integer; hash: TDCP_hashclass): ansistring;var  i: Integer;begin  Result := pass+salt;  for i := 0 to count-1 do    Result := CalcDigest(Result, hash);end;function PBKDF2(pass, salt: ansistring; count, kLen: Integer; hash: TDCP_hashclass): ansistring;  function IntX(i: Integer): ansistring; inline;  begin    Result := Char(i shr 24) + Char(i shr 16) + Char(i shr 8) + Char(i);  end;var  D, I, J: Integer;  T, F, U: ansistring;begin  T := '';  D := Ceil(kLen / (hash.GetHashSize div 8));  for i := 1 to D do  begin    F := CalcHMAC(salt + IntX(i), pass, hash);    U := F;    for j := 2 to count do    begin      U := CalcHMAC(U, pass, hash);      F := XorBlock(F, U);    end;    T := T + F;  end;  Result := Copy(T, 1, kLen);end;end.

Из бросающегося в глаза - обратите внимание, что в Pascal и его потомках отсутствует классическое разделение на заголовочные файлы и файлы собственно с кодом, в этом смысле модульная организация роднит его с Python, и отличает от C.

Однако от питонячьего модуля паскалевский отличается ещё и тем, что "снаружи" доступны только те функции/переменные, которые объявлены в секции interface. То есть по умолчанию внутри модуля ты можешь хоть "на ушах стоять" - снаружи никто не сможет вызвать твои внутренние API. Так устроен язык, а хорошо это или плохо - вопрос вкуса, поэтому оценки оставим в стороне (питонистам передают привет функции/методы, начинающиеся на "_" и "__").

Заголовочная часть

Код, как обычно, под спойлером.

Заголовочная часть ("шапка", header)
program devault;uses  math, sysutils, strutils, getopts, DCPcrypt2, DCPsha256, DCPrijndael, kdf;

Далее нам понадобится пара функций - hexlify и unhexlify (набросаны, конечно, "на скорую руку"). Они являются аналогами соответствующих функций Python - вторая возвращает строку из шестнадцатеричных представлений байтов входного аргумента, а первая - наоборот, переводит строку шестнадцатеричных кодов обратно в байты.

hexlify/unhexlify
function unhexlify(s:AnsiString):AnsiString;var i:integer;    tmpstr:AnsiString;begin  tmpstr:='';  for i:=0 to (length(s) div 2)-1 do    tmpstr:=tmpstr+char(Hex2Dec(Copy(s,i*2+1,2)));  unhexlify:=tmpstr;end;function hexlify(s:AnsiString):AnsiString;var i:integer;    tmpstr:AnsiString;begin  tmpstr:='';  for i:=1 to (length(s)) do    tmpstr:=tmpstr+IntToHex(ord(s[i]),2);  hexlify:=tmpstr;end;

Назначение функций showbanner(), showlicense() и showhelp() очевидно из названий, поэтому я просто приведу их без комментариев.

showbanner() / showlicense() / showhelp()
showbanner()
procedure showbanner();begin  WriteLn(stderr, 'DeVault v1.0');  Writeln(stderr, '(C) 2021, Sergey Pechenko. All rights reserved');  Writeln(stderr, 'Run with "-l" option to see license');end;
showlicense()
procedure showlicense();begin  WriteLn(stderr,'Redistribution and use in source and binary forms, with or without modification,');  WriteLn(stderr,'are permitted provided that the following conditions are met:');  WriteLn(stderr,'* Redistributions of source code must retain the above copyright notice, this');  WriteLn(stderr,'   list of conditions and the following disclaimer;');  WriteLn(stderr,'* Redistributions in binary form must reproduce the above copyright notice, ');  WriteLn(stderr,'   this list of conditions and the following disclaimer in the documentation');  WriteLn(stderr,'   and/or other materials provided with the distribution.');  WriteLn(stderr,'* Sergey Pechenko''s name may not be used to endorse or promote products');  WriteLn(stderr,'   derived from this software without specific prior written permission.');  WriteLn(stderr,'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"');  WriteLn(stderr,'AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,');  WriteLn(stderr,'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE');  WriteLn(stderr,'ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE');  WriteLn(stderr,'FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES');  WriteLn(stderr,'(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;');  WriteLn(stderr,'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON');  WriteLn(stderr,'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT');  WriteLn(stderr,'(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,');  WriteLn(stderr,'EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.');  WriteLn(stderr,'Commercial license can be obtained from author');end;
showhelp()
procedure showhelp();begin  WriteLn(stderr,'Usage:');  WriteLn(stderr,Format('%s <-p password | -w vault_password_file> [-f secret_file]',[ParamStr(0)]));  WriteLn(stderr,#09'"password" is a text string which was used to encrypt your secured content');  WriteLn(stderr,#09'"vault_password_file" is a file with password');  WriteLn(stderr,#09'"secret_file" is a file with encrypted content');  WriteLn(stderr,'When "-f" argument is absent, stdin is read by default');end;

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

Переменные и константы
var secretfile, passwordfile, pass, salt, b_derived_key, b_key1, b_key2, b_iv,    hmac_new, cphrtxt, fullfile, header, tmpstr, hmac:Ansistring;    Cipher: TDCP_rijndael;    key, vector, data, crypt: RawByteString;    fulllist: TStringArray;    F: Text;    c: char;    opt_idx: LongInt;    options: array of TOption;const KEYLENGTH=32; // for AES256const IV_LENGTH=128 div 8;const CONST_HEADER='$ANSIBLE_VAULT;1.1;AES256';

Код

Ну, почти код - всё ещё вспомогательная функция, которая в рантайме готовит массив записей для разбора параметров командной строки. Почему она здесь - потому что работает с переменными, объявленными в секции vars выше.

preparecliparams()
procedure preparecliparams();begin  SetLength(options, 6);  with options[1] do    begin      name:='password';      has_arg:=Required_Argument;      flag:=nil;      value:=#0;    end;  with options[2] do    begin      name:='file';      has_arg:=Required_Argument;      flag:=nil;      value:=#0;    end;  with options[3] do    begin      name:='passwordfile';      has_arg:=Required_Argument;      flag:=nil;      value:=#0;    end;  with options[4] do    begin      name:='version';      has_arg:=No_Argument;      flag:=nil;      value:=#0;    end;  with options[5] do    begin      name:='license';      has_arg:=No_Argument;      flag:=nil;      value:=#0;    end;  with options[6] do    begin      name:='help';      has_arg:=No_Argument;      flag:=nil;      value:=#0;    end;end;

А вот теперь точно код самой утилиты:

Весь остальной код
begin  repeat    c:=getlongopts('p:f:w:lh?',@options[1],opt_idx);    case c of      'h','?' : begin showhelp(); halt(0); end;      'p' : pass:=optarg;      'f' : secretfile:=optarg;      'w' : passwordfile:=optarg;      'v' : begin showbanner(); halt(0); end;      'l' : begin showlicense(); halt(0); end;      ':' : writeln ('Error with opt : ',optopt); // not a mistake - defined in getops unit     end;  until c=endofoptions;  if pass = '' then // option -p not set    if passwordfile <> '' then      try        Assign(F,passwordfile);        Reset(F);        Readln(F,pass);        Close(F);      except        on E: EInOutError do        begin          Close(F);          writeln(stderr, 'Password not set and password file cannot be read, exiting');          halt(1);        end;      end    else      begin // options -p and -w are both not set          writeln(stderr, 'Password not set, password file not set, exiting');          showhelp();          halt(1);      end;  try    Assign(F,secretfile);    Reset(F);  except    on E: EInOutError do    begin      writeln(stderr, Format('File %s not found, exiting',[secretfile]));      halt(1);    end;  end;  readln(F,header);  if header<>CONST_HEADER then    begin      writeln(stderr, 'Header mismatch');      halt(1);    end;  fullfile:='';  while not EOF(F) do    begin    Readln(F,tmpstr);    fullfile:=fullfile+tmpstr;    end;  Close(F);  fulllist:=unhexlify(fullfile).Split([#10],3);  salt:=fulllist[0];  hmac:=fulllist[1];  cphrtxt:=fulllist[2];  salt:=unhexlify(salt);  cphrtxt:=unhexlify(cphrtxt);  b_derived_key:=PBKDF2(pass, salt, 10000, 2*32+16, TDCP_sha256);  b_key1:=Copy(b_derived_key,1,KEYLENGTH);  b_key2:=Copy(b_derived_key,KEYLENGTH+1,KEYLENGTH);  b_iv:=Copy(b_derived_key,KEYLENGTH*2+1,IV_LENGTH);  hmac_new:=lowercase(hexlify(CalcHMAC(cphrtxt, b_key2, TDCP_sha256)));  if hmac_new<>hmac then    begin    writeln(stderr, 'Digest mismatch - file has been tampered with, or an error has occured');    Halt(1);    end;  SetLength(data, Length(crypt));  Cipher := TDCP_rijndael.Create(nil);  try    Cipher.Init(b_key1[1], 256, @b_iv[1]);    Cipher.DecryptCTR(cphrtxt[1], data[1], Length(data));    Cipher.Burn;  finally    Cipher.Free;  end;  Writeln(data);end.

Дальше будет странная таблица, но, кажется, это - самый удобный способ рассказа об исходном коде.

Стр.

Назначение

2-13

разбор параметров командной строки с отображением нужных сообщений;

14-34

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

35-44

попытка прочесть зашифрованный файл, указанный в параметрах;

Небольшой чит: по умолчанию имя файла (переменная secretfile) равно пустой строке; в этом случае вызов Assign(F, secretfile) в строке 36 свяжет переменную F с stdin

45-50

проверка наличия в файле того самого заголовка $ANSIBLE_VAULT;1.1;AES256;

51-57

читаем всё содержимое зашифрованного файла и закрываем его;

58-63

разбираем файл на части: "соль", дайджест, шифртекст - всё отдельно; при этом все три части нужно будет ещё раз прогнать через unhexlify (помните примечание в VaultAES256.encrypt?)

64-73

вычисление производного ключевого материала; разбиение его на части; расчёт дайджеста; проверка зашифрованного файла на корректность дайждеста;

74-83

подготовка буфера для расшифрованного текста; расшифровка; затирание ключей в памяти случайными данными; вывод расшифрованного содержимого в поток stdout

Интересная информация для питонистов

Кстати, вы же слышали, что в Python 3.10 наконец-то завезли оператор case (PEP-634)? Интересно, что его ввёл сам BDFL, и произошло это примерно через 14 лет после того, как по результатам опроса на PyCon 2007 первоначальный PEP-3103 был отвергнут.

Собственно, теперь всё на месте, осталось собрать:

[root@ansible devault]# time fpc devault.pas -Fudcpcrypt_2.1:dcpcrypt_2.1/Ciphers:dcpcrypt_2.1/Hashes -MOBJFPC

Здесь имейте в виду, что форматирование Хабра играет злую шутку - никакого разрыва строки после первого минуса нет.

Вывод компилятора
Free Pascal Compiler version 3.0.4 [2017/10/02] for x86_64Copyright (c) 1993-2017 by Florian Klaempfl and othersTarget OS: Linux for x86-64Compiling devault.pasCompiling ./dcpcrypt_2.1/DCPcrypt2.pasCompiling ./dcpcrypt_2.1/DCPbase64.pasCompiling ./dcpcrypt_2.1/Hashes/DCPsha256.pasCompiling ./dcpcrypt_2.1/DCPconst.pasCompiling ./dcpcrypt_2.1/Ciphers/DCPrijndael.pasCompiling ./dcpcrypt_2.1/DCPblockciphers.pasCompiling kdf.pasLinking devault/usr/bin/ld: warning: link.res contains output sections; did you forget -T?3784 lines compiled, 0.5 secreal    0m0.543suser    0m0.457ssys     0m0.084s

Вроде неплохо: 3,8 тысячи строк кода собраны до исполняемого файла за 0.6 сек. На выходе - статически связанный бинарник, которому для работы от системы требуется только ядро. Ну то есть для запуска достаточно просто скопировать этот бинарник в файловую систему - и всё. Кстати, я забыл указать его размер: 875К. Никаких зависимостей, компиляций по несколько минут и т.д.

Ах да, чуть не забыл самое интересное! Запускаем, предварительно сложив пароль в файл ".password":

[root@ansible devault]# ./devault -w .password -f vaulted.yml---collections:- name: community.general  scm: git  src: https://github.com/ansible-collections/community.general.git  version: 1.0.0

Вот такой нехитрый YaML я использовал в самом начале статьи для создания зашифрованного файла.

Исходный код для самостоятельного изучения можно взять здесь.

Хотите ещё Ansible? (осторожно, денежные вопросы!)

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

Если же хотите систематизировать и углубить свои знания Ansible - я провожу тренинги по Ansible, пишите мне в Telegram.

Подробнее..

Какой CICD-инструмент выбрать Jenkins или GitLab?

01.02.2021 14:09:27 | Автор: admin
Инструменты непрерывной интеграции и развертывания CI/CD на сегодня довольно востребованы. Из всех актуальных решений есть два очевидных лидера, Jenkins и GitLab. На крупных сервисах отзывов у обоих решений примерно одинаковый рейтинг, но смотреть стоит не только на это. Давайте разберемся с преимуществами Jenkins и GitLab, и для каких задач они лучше всего подходят.



GitLab


Это бесплатный opensource-продукт, выпущенный под лицензией MIT и написанный на языках Go и Ruby. Отдельный сервер на таком решении способен работать более чем с 25 000 пользователями.


Интерфейс GitLab

GitLab дает возможности работы с репозиториями, ревьюить код, имеет собственную систему контроля ошибок и многое другое. Для повышения конфиденциальности пользователей есть возможность связать инструмент с Active Directory и с LDAP-серверами, установив его локально.

Большое и вовлеченное сообщество делает работу с продуктом комфортной. GitLab используется не только для создания кода, но и для его тщательной проверки. Поддерживаются практически все среды сборки и системы контроля версий.

Плюсы


  • Подробная документация и простое управление.
  • Удобный пользовательский интерфейс для наблюдения за результатами тестирования. Можно дать права на чтение и изменение как отдельным людям, так и группе пользователей.
  • Удобный инструмент для установки майлстоунов, что позволяет оперативно отслеживать и решать проблемы.
  • Легкое назначение контрольных точек проекта и их группировка по задачам.
  • Удобное параллельное тестирование pull requests и веток, что делает его хорошим выбором для opensource-проектов.

Минусы


  • Артефакты (файлы, которые сохранить после сборки) требуется определять и загружать для каждого задания.
  • Этапы внутри больших задач пока не поддерживаются.

Jenkins


Расширяемое opensource-решение для автоматизации развертывания. Jenkins написан на Java и тоже работает под лицензией MIT. У него богатый набор функций для автоматизации задач сборки, тестирования, развертывания, интеграции и релиза программного обеспечения.


Интерфейс Jenkins

Кроме инсталяции через традиционный установочный пакет он может быть установлен как автономно, так и в качестве Docker на любой машине с установленной Java Runtime Environment (JRE).

Существует также подпроект команды Jenkins под названием Jenkins X, который специализируется на CI/CD в рамках кластеров Kubernetes.

Команда Jenkins выпустила около 1 500 плагинов, благодаря чему его можно использовать вместе с другими решениями например, co Slack, Jira и другими. Интеграция также доступна для ряда инструментов тестирования DevOps. Есть поддержка REST API для удаленного доступа к системе. Существует три его варианта: Python, XML и JSON с поддержкой JSONP. Как и в случае с GitLab, продукт помогает развивать большое неравнодушное сообщество. Также решение может работать в качестве сервлета в контейнерах Java, таких как GlassFish и Apache Tomcat.

Плюсы


  • Простота настройки и обновления (всего за несколько шагов).
  • Автоматизированный процесс сборки и подробная понятная документация.
  • Легкая интеграция с другими инструментами, в этом случае вы можете получать уведомление о ходе процесса.
  • Использование нескольких машин для распределенных сборок. Это полезно в задачах, когда нужно протестировать продукт в нескольких разных средах.

Минусы


  • Сложная интеграция плагинов.
  • Решение не очень подходит для небольших проектов, так как его настройка довольно трудоемкая.

Суммируем


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

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

С помощью GitLab можно контролировать все аспекты работы с Git-репозиториями, включая ветки с кодом С Jenkins же вы контролируете репозитории только до некоторой степени. Например, ветки вы контролируете не полностью.

Также стоит помнить изначальную задачу, которая стояла при разработке обоих инструментов. Jenkins создавался в первую очередь для реализации CI, а GitLab для совместной работы с кодом и контроля версий.



Блог ITGLOBAL.COM Managed IT, частные облака, IaaS, услуги ИБ для бизнеса:

Подробнее..

Nuke. Быстрый старт

19.01.2021 10:15:06 | Автор: admin

Послепрочтениястатьи"КакготовитьCake,используятолькоFrosting"мнепришлавголову мысль:"Какойбольшойпроектдлятакогопростогопроцессасборки".Послеэтогояирешилнаписатьмини-статьюпроаналогCakeNuke.

Если я правильно понимаю историю проекта, Nuke появился как более простой и удобный аналог Cake, Psake и Fake. Автору Nuke хотелось писать скрипты сборки именно на C#, поэтому ему не подошли Psake и Fake. Судя по всему, когда создавался Nuke, не существовал Frosting, и все Cake скрипты были странными файлами с DSL на основе C#, которые можно было писать и отлаживать только в VS Code. Скрипт сборки Nuke изначально задумывался как обычное консольное приложение, которое легко можно писать и отлаживать в любой IDE.

ДавайтесоздадимпростейшийскриптсборкинаNukeисоберёмсегопомощьюприложение!

1. Создаёмприложение

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

2. Устанавливаем Global Tool

dotnet tool install Nuke.GlobalTool --global

3. Создаём проект со скриптом сборки

Дляэтогонеобходимовыполнитькоманду:

nuke :setup

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

Давайте посмотрим, что изменилось в репозитории:

Если не трогать настройки по умолчанию, то скрипт установки nuke создаст проект сборки в отдельной папке build репозитория. Таким образом, скрипты сборки лежат в build, а исходники в src. Те же настройки по умолчанию предполагают использование папки output в корне репозитория в качестве выходной директории для сборки.

Разберём изменения по отдельности:

  • .nuke файл-маркер, по которому nuke определяет корневую папку

  • build.* бутстрапперы для запуска сборки. При необходимости могут и .net установить, если его нет на машине, на которой происходит сборка

  • _build.csproj файл проекта сборки. Имеет такое странное название для того, чтобы всегда быть первым в списке проектов в Solution Explorer

  • .editorconfig и _build.csproj.DotSettings просто настройки стиля

А теперь самое интересное:

3.1. Изменения в sln

Проект _build был добавлен в решение. Но был добавлен очень хитрым способом. Он отображается в IDE, его можно собрать, но если выполнить сборку всего решения, то мы увидим следующий вывод:

1>------ Rebuild All started: Project: Demo, Configuration: Debug Any CPU ------2>------ Skipped Rebuild All: Project: _build, Configuration: Debug Any CPU ------2>Project not selected to build for this solution configuration 1>Demo -> C:\Users\buldo\source\repos\nuke-example\src\Demo\Demo\bin\Debug\netcoreapp3.1\Demo.dll========== Rebuild All: 1 succeeded, 0 failed, 1 skipped ==========

То есть при пересборке решения проект _build не собирается. Действительно, если бы скрипт сборки при работе вызывал ещё и пересборку самого себя, это могло бы привести к проблемам.

3.2. Build.cs

Приведу полный код сгенерированного файла и объясню основные моменты.

[CheckBuildProjectConfigurations][ShutdownDotNetAfterServerBuild]class Build : NukeBuild{    public static int Main () => Execute<Build>(x => x.Compile);    [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]    readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;    [Solution] readonly Solution Solution;    [GitRepository] readonly GitRepository GitRepository;    [GitVersion] readonly GitVersion GitVersion;    AbsolutePath SourceDirectory => RootDirectory / "src";    AbsolutePath OutputDirectory => RootDirectory / "output";    Target Clean => _ => _        .Before(Restore)        .Executes(() =>        {            SourceDirectory.GlobDirectories("**/bin", "**/obj").ForEach(DeleteDirectory);            EnsureCleanDirectory(OutputDirectory);        });    Target Restore => _ => _        .Executes(() =>        {            DotNetRestore(s => s                .SetProjectFile(Solution));        });    Target Compile => _ => _        .DependsOn(Restore)        .Executes(() =>        {            DotNetBuild(s => s                .SetProjectFile(Solution)                .SetConfiguration(Configuration)                .SetAssemblyVersion(GitVersion.AssemblySemVer)                .SetFileVersion(GitVersion.AssemblySemFileVer)                .SetInformationalVersion(GitVersion.InformationalVersion)                .EnableNoRestore());        });}

Данный класс является точкой входа в приложения. В методе Main запускается сборка и выбирается цель сборки по умолчанию.

Цели сборки представлены свойствами типа Target. Синтаксис с кучей стрелочек сначала пугает, но потом привыкаешь. Для целей сборки можно задавать зависимости (DependsOn()), явный порядок выполнения (Before(), After()), условия выполнения (как статические, так и динамические), а главное указывать с помощью Executes(), что вообще делает этот Target.

Следующая важная вещь для начинающего пользователя Nuke параметры сборки. Достаточно просто пометить поле атрибутом [Parameter], и можно передавать значение этого поля через командную строку. В данном случае конфигурацию сборки Debug или Release. Механизм очень гибок можно сделать параметр необходимым, и без него сборка не запустится. Также параметр можно делать необходимым только для конкретного Target.

Nuke предоставляет необходимые абстракции над решениями и проектами. Несколько решений в проекте? Нет проблем. Добавьте новое свойство типа Solution и пометьте его атрибутом [Solution] Nuke найдёт решение, распарсит его и предоставит доступ его содержимому.

Также в этом файле можно заметить пример расширения Nuke модуль для работы с git установлен отдельным пакетом. С помощью полей GitRepository и GitVersion можно легко оперировать состоянием репозитория. Например, ориентируясь на имя ветки (master/не master), выбрать ставить или нет preview метку при сборке nuget пакета.

4. Запуск сборки

Сборка запускается с помощью бутстраппера:

.\build.ps1 [targets] [arguments]

В данном случае для того, чтобы собрать приложение, необходимо выполнить следующую команду:

.\build.ps1 --target Compile --configuration release

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

TargetStatusDurationRestoreExecuted0:01CompileExecuted0:03Total0:04Build succeeded on 29.12.2020 21:38:10.

На самом деле, если установлен NET 5, сборка скорее всего завершится ошибкой. Волшебный фикс заменить атрибут поля GitVersion на [GitVersion(Framework = "netcoreapp3.1")].

5. Делаем что-то полезное

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

Далее я приведу код цели сборки с подробными комментариями:

Target Publish => _ => _    .Executes(() =>    {        var rids = new[] {"win-x64", "linux-x64"}; // Перечисляем RID'ы, для которых собираем приложение        DotNetPublish(s => s // Теперь вызываем dotnet publish            .SetAssemblyVersion(GitVersion.AssemblySemVer)            .SetFileVersion(GitVersion.AssemblySemFileVer)            .SetInformationalVersion(GitVersion.InformationalVersion)            .SetProject(Solution.GetProject("Demo")) // Для dotnet publish желательно указывать проект            .SetPublishSingleFile(true) // Собираем в один файл            .SetSelfContained(true)     // Вместе с рантаймом            .SetConfiguration(Configuration) // Для определённой конфигурации            .CombineWith(rids, (s, rid) => s // Но нам нужны разные комбинации параметров                .SetRuntime(rid) // Устанавливаем RID                .SetOutput(OutputDirectory/rid))); // Делаем так, чтобы сборки с разными RID попали в разные папки    });

Заключение

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

Подробнее..
Категории: C , Ci/cd , Net , Nuke

Перевод Вышел релиз GitLab 13.7 с проверяющими для мерж-реквестов и автоматическим откатом при сбое

12.01.2021 16:20:24 | Автор: admin

Картинка для привлечения внимания


Ну и год же был 2020! Мы счастливы представить релиз 13.7 с более чем 45 фичами и улучшениями поставки ПО, вышедший как раз к праздникам.


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


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


Вот что вас ждёт в релизе 13.7:


Улучшенное управление проектами для развития совместной работы


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


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


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


Улучшена автоматизация релизов и гибкость развёртывания


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


Чтобы улучшить автоматизацию релизов в GitLab, мы добавили автоматический откат в случае сбоя. Эта фича отменяет неудачное развёртывание, восстанавливает последнее успешное развёртывание и посылает автоматическое уведомление об этом. Вам не придётся вносить изменения вручную, и вы можете быть уверены, что потенциальные проблемы не приведут к простоям и ситуация не ухудшится, пока вы работаете над устранением неполадок.


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


Мы также выпустили первую официально поддерживаемую бета-версию контейнера обработчика заданий GitLab для Red Hat OpenShift, а также нашего сертифицированного оператора обработчиков заданий, чтобы дать вам больше свободы в том, как вы выпускаете релизы с GitLab. Мы работаем над тем, чтобы сделать эту фичу общедоступной, так что следите за новостями в будущих релизах.


Более надёжное и эффективное управление пакетами и зависимостями


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


Мы также внесли улучшения в прокси зависимостей от GitLab; кстати, эта фича была перенесена в Core в GitLab 13.6.


Теперь вы можете вписаться в ограничения запросов Docker и ускорить работу конвейеров (в русской локализации GitLab сборочные линии) благодаря кэшированию образов контейнеров, размещённых на DockerHub, и быть уверенными в надёжности и эффективности работы с образами.


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


И, наконец, вы можете использовать предопределённые переменные с прокси зависимостей взамен того, чтобы полагаться на свои собственные определённые переменные или вшитые значения в вашем файле gitlab.ci-yml. Таким образом, появился более масштабируемый и эффективный способ начать проксирование и кэширование образов.


И это ещё не всё!


Взгляните на ещё несколько классных новых фич релиза 13.7:



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


6-7го января у нас прошёл виртуальный хакатон, узнайте больше об этом и будущих мероприятиях от GitLab здесь.


GitLab MVP badge


MVP этого месяца Rachel Gottesman


Rachel активно помогала нашей команде технических писателей внедрить согласованный стиль в документации для исправления использования будущего времени в наших документах. В релизе 13.7 Rachel открыла 33 мерж-реквеста, чем помогла нашей команде справиться с этой важной и кропотливой задачей. Спасибо, Rachel!


Основные фичи релиза GitLab 13.7


Проверяющие для мерж-реквестов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


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


GitLab 13.7 представляет новую фичу теперь авторы мерж-реквеста могут запросить ревью у конкретных пользователей. В новом поле Reviewers пользователи могут быть назначены проверяющими для мерж-реквеста аналогичным образом, как назначаются ответственные (assignee). Назначенные на ревью пользователи получат уведомление, предлагающее им просмотреть мерж-реквест. Таким образом, теперь существует формальный процесс запроса ревью для мерж-реквеста и уточняются роли каждого пользователя в работе над ним.


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


Reviewers for Merge Requests


Документация по назначению проверяющих для мерж-реквеста и оригинальный тикет.


Автоматический откат в случае сбоя


(ULTIMATE, GOLD) Стадия цикла DevOps: Release


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



Документация по автоматическому откату при сбое и оригинальный тикет.


Клонирование тикета через быстрое действие


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


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


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


Clone an issue with a quick action


Документация по быстрым действиям и оригинальный тикет.


Обработчик заданий GitLab для Red Hat OpenShift


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Наконец-то стал доступен образ контейнера обработчика заданий GitLab (GitLab runner) для платформы контейнеров Red Hat OpenShift! Чтобы установить обработчик заданий на OpenShift, воспользуйтесь новым оператором обработчиков заданий GitLab. Он доступен на бета-канале в Red Hat's Operator Hub веб-консоли для администраторов кластеров OpenShift, уже развёрнутой по умолчанию на платформе, где они могут найти и выбрать операторы для установки на своём кластере. На платформе контейнеров OpenShift Operator Hub уже развёрнут по умолчанию. Мы планируем перенести оператор обработчика заданий GitLab на стабильный канал, а в начале 2021 года в общий доступ. Наконец, мы также разрабатываем оператор для GitLab, так что следите за будущими публикациями.


GitLab Runner for Red Hat OpenShift


Документация по установке на OpenShift и оригинальный тикет.


Просмотр статуса развёртываний на странице окружений


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


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


Show deployment status on the Environments page


Документация по работе с окружениями и оригинальный тикет.


Задавайте через пользовательский интерфейс процент трафика для канареечного развёртывания


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Release


В GitLab 13.7 вы можете менять процент трафика для канареечного развёртывания (значение canary-weight) непосредственно с досок развёртывания в пользовательском интерфейсе. Вы также можете менять это значение из gitlab-ci.yml и через API, но сделав это в пользовательском интерфейсе, вы сможете наблюдать за развёртыванием и при необходимости отмасштабировать поды прямо с досок развёртывания. Так у вас будет больше контроля над ручными или инкрементальными развёртываниями по таймеру, а также вы сможете лучше контролировать и даже снижать риски.


Set deployment traffic weight via the UI


Документация по заданию процента трафика для канареечного развёртывания и оригинальный тикет.


Просмотр частоты развёртываний через API


(ULTIMATE, GOLD) Стадия цикла DevOps: Release


В этом релизе в рамках первой итерации встроенной в GitLab поддержки метрик DORA4 была добавлена возможность узнавать частоту развёртываний на уровне проекта через API. Это позволяет отслеживать эффективность развёртывания с течением времени, легко находить узкие места и при необходимости быстро принимать меры по корректировке.


API support for deployment frequency


Документация по аналитике проектов и оригинальный тикет.


Поддержка нескольких файлов манифеста в проекте


(PREMIUM, ULTIMATE) Стадия цикла DevOps: Configure


В предыдущих релизах для использования нашего агента для Kubernetes (GitLab Kubernetes Agent) требовалось, чтобы пользователи собирали все ресурсы Kubernetes в один файл манифеста. Теперь же агент может собирать манифесты Kubernetes рекурсивно из указанных каталогов в вашем проекте. Ваши специалисты по платформе теперь смогут использовать один репозиторий для управления различными кластерами из единого места, а также описывать крупные развёртывания с помощью одного агента.


Support multiple manifest files in a project


Документация по настройке репозитория с агентом Kubernetes и оригинальный тикет.


Импорт требований из внешних инструментов


(ULTIMATE, GOLD) Стадия цикла DevOps: Plan


Для эффективной совместной работы очень важно, чтобы все ваши требования хранились в одном месте, поэтому мы рады сообщить, что теперь вы можете импортировать требования из CSV-файлов!


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


Import requirements from external tools


Документация по импорту требований из CSV-файла и оригинальный тикет.


Несколько конечных точек HTTP для оповещений


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


Integrate alerting tools with multiple HTTP endpoints


Документация по конечным точкам для оповещений и оригинальный эпик.


Синхронизация групп на GitLab.com с помощью SAML


(SILVER, GOLD) Стадия цикла DevOps: Manage


В GitLab 13.7 вы можете привязать группу в вашем поставщике учётных записей к группе на GitLab.com с помощью SAML. Членство в группе будет обновляться, когда пользователь войдёт в учётную запись GitLab через своего провайдера SAML. Эта фича снижает необходимость в ручном назначении групп, что снижает загрузку по группам для администраторов GitLab. Синхронизация групп также улучшает адаптацию новых членов групп, избавляя их от необходимости запрашивать доступ у администраторов групп GitLab.


SAML Group Sync for GitLab.com


Документация по синхронизации групп с помощью SAML и оригинальный эпик.


Другие улучшения в GitLab 13.7


DevOps Adoption


(ULTIMATE) Стадия цикла DevOps: Manage


DevOps Adoption показывает вам, какие команды в вашей организации используют тикеты, мерж-реквесты, подтверждения, обработчики заданий, конвейеры, развёртывания и сканирования в GitLab. Используйте также новую фичу сегменты, чтобы собрать ваши группы GitLab в логические единицы в рамках вашей организации, чтобы вы могли сравнивать, как используют GitLab среди нескольких разных групп.


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

DevOps Adoption


Документация по DevOps Adoption и оригинальный тикет.


Улучшенный пользовательский интерфейс для создания проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


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


Документация по созданию проектов и оригинальный тикет.


Ограничение создания проектов и групп для внешних аккаунтов


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


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


Документация по настройкам пользователя через SAML и оригинальный тикет.


Сортировка по числу блокируемых тикетов


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


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


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


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


Sort issues by the number of issues they are blocking


Документация по сортировке и оригинальный тикет.


Просмотр файлов в мерж-реквестах по одному


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


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


В GitLab 13.7 мы добавили возможность просматривать файлы по одному при просмотре мерж-реквеста. При переходе на вкладку мерж-реквеста Изменения кликните на иконку с шестерёнками и поставьте галочку Показывать файлы по одному. После выбора этого параметра вы сможете просматривать файлы по одному, переключаясь между ними при помощи кнопок Предыдущий и Следующий.


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


Choose to show one file at a time directly from merge requests


Документация по ревью и управлению мерж-реквестами и оригинальный тикет.


Просмотр изменений мерж-реквеста в VS Code


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


При ревью мерж-реквестов в VS Code для обращения к изменениям зачастую приходится делать checkout ветки и затем пытаться разобраться в диффе между этой веткой и целевой веткой мержа.


С релизом 3.7.0 расширения GitLab Workflow изменения мерж-реквеста стали доступны напрямую в VS Code. Это позволяет быстро просматривать изменения в мерж-реквестах ваших проектов.


В рамках работы над добавлением полноценного ревью кода в VS Code следующим шагом мы собираемся добавить комментарии к диффам.


View Merge Request changes in VS Code


Документация по расширению для VS Code и оригинальный тикет.


Улучшенное скачивание артефактов для вложенных конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


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


Improved artifact downloads with child pipelines


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


Обход ограничений Docker и ускорение конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package
Для более быстрых и надёжных сборок вы можете использовать нашу фичу, прокси зависимостей, для кэширования образов контейнеров из Docker Hub. Однако, когда Docker начал применять ограничения по количеству запросов docker pull, вы могли заметить, что даже когда ваш образ скачивался из кэша, Docker всё равно засчитывал его в лимит. Это происходило потому, что прокси зависимостей кэшировал только слои (или блоб-объекты) образа, но не манифест, который содержит информацию о том, как собрать данный образ. Так как манифест был необходим для сборки, всё равно приходилось выполнять pull. А если Docker Hub был недоступен, вы не могли скачать нужный образ.
Начиная с этого релиза прокси зависимостей будет кэшировать и слои, и манифест образа. Так что при первом скачивании с использованием alpine:latest образ будет добавлен в кэш прокси зависимостей, и это будет считаться за один pull. В следующий раз, когда вы будете скачивать alpine:latest, всё будет скачиваться из кэша, даже если Docker Hub недоступен, и это скачивание не будет учитываться в лимите Docker.


Напоминаем вам, что начиная с 13.6 прокси зависимостей стал доступен в плане Core. Поэтому попробуйте эту фичу сейчас и скажите нам, что вы о ней думаете. Или даже лучше, помогите нам с открытыми тикетами.



Документация по прокси зависимостей и оригинальный тикет.


Быстрый поиск и просмотр общих пакетов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


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


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



Документация по просмотру пакетов и оригинальный тикет.


Прокси зависимостей для приватных проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


Вы можете использовать прокси зависимостей GitLab для проксирования и кэширования образов контейнеров из Docker Hub. До последнего времени эта фича была доступна только для публичных групп, что не позволяло многим пользователям её использовать.


Теперь вы можете использовать прокси зависимостей и для приватных проектов. Вы можете снизить свои скачивания с Docker Hub путём кэширования ваших образов контейнера для использования их в будущем. Так как прокси зависимостей хранит образы Docker в пространстве, связанном с вашей группой, вы должны авторизоваться с вашим логином и паролем GitLab или с личным токеном доступа, для которого есть разрешение как минимум на чтение (read_registry).


Документация по прокси зависимостей и оригинальный тикет.


Улучшенная поддержка анализаторов SAST для нескольких проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Secure


В GitLab сканирования безопасности автоматически определяют язык кода и запускают подходящие анализаторы. В случае монорепозиториев, микросервисов и репозиториев для нескольких проектов в одном репозитории GitLab может существовать больше одного проекта. Ранее наши инструменты безопасности могли определять язык кода только в одиночных проектах в репозиториях. Начиная с этого релиза наши анализаторы SAST могут определять языки кода в репозиториях с несколькими проектами, запускать подходящие сканирования для каждого проекта и составлять отчёт о уязвимостях. Это делает
управление инструментами безопасности проще и удобнее для пользователей с одним репозиторием для нескольких проектов. В следующих релизах мы продолжим улучшать панель безопасности и отчёты для этих типов проектов.


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


Описание релиза во внешнем файле


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


Если вы создаёте релизы в конвейерах через файл .gitlab-ci.yml вашего проекта, вам, возможно, было сложно поддерживать в актуальном состоянии описание каждого релиза. В релизе GitLab 13.7 вы можете задавать описание вашего релиза в файле с контролем версий или в автоматически генерируемом файле и вызывать его из .gitlab-ci.yml. При этом содержимое файла загружается в описание релиза в формате Markdown. Это упрощает создание, поддержку и использование контроля версий для релизов, а также будет особенно полезно при автогенерации лога изменений. Огромное спасибо Nejc Habjan и Siemens за этот невероятный вклад!



Документация по описаниям релизов и оригинальный тикет.


Поддержка для версий Kubernetes 1.17, 1.18 и 1.19


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Configure


Поддержка GitLab для последних версий Kubernetes позволяет вам пользоваться преимуществами интеграций GitLab с Kubernetes, такими как GitLab Kubernetes Agent, Auto DevOps и на более поздних кластерах GitLab Managed Apps. В этом релизе GitLab добавил официальную поддержку для версий Kubernetes 1.17, 1.18 и 1.19.


Документация по кластерам и оригинальный тикет.


Geo поддерживает репликацию сниппетов


(PREMIUM, ULTIMATE) Доступность


Geo теперь поддерживает репликацию сниппетов под контролем версий на вторичные ноды, что позволит распределённым командам получать доступ к ним с ближайшей ноды Geo, что снижает задержку и делает весь процесс удобнее. Кроме того, эти данные могут быть восстановлены со вторичной ноды при переключении на неё в случае сбоя.


В данный момент мы не поддерживаем верификацию для этого типа данных, но мы планируем добавить её в будущем.


Документация по репликации Geo и оригинальный эпик.


Поддержка зашифрованных учётных данных LDAP


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


GitLab использует единый файл конфигурации, например gitlab.rb в Omnibus GitLab, что упрощает настройку всех связанных сервисов. В этот файл конфигурации включены некоторые секретные ключи, например учётные данные для аутентификации на сервере LDAP. Хотя для доступа к этому файлу требуются специальные права, хорошей практикой считается отделять секретные ключи от конфигурации.


Установки Omnibus GitLab и Source теперь поддерживают зашифрованные учётные данные, причём первыми поддерживаемыми учётными данными стали LDAP. Это снижает уязвимость конфигурационного файла GitLab, а также помогает достичь соответствия требованиям заказчика.


Документация по настройке зашифрованных учётных данных LDAP и оригинальный тикет.


Веб-хуки при добавлении новых участников группы


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


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


Документация по веб-хукам и оригинальный тикет.


Улучшенная фильтрация и сортировка списков участников группы


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


Мы продолжили улучшать наш список участников группы и добавили для него новые возможности фильтрации и сортировки. Это поможет администраторам группы быстро находить нужную им информацию. Например, сортировку по последнему времени входа (Last sign-in) можно использовать для поиска пользователей, которые в последнее время не заходили на GitLab, и для помощи в управлении лицензиями.


Improved group members list filtering and sorting


Документация по фильтрации и сортировке участников группы и оригинальный тикет.


Автоматическая подготовка профиля пользователя с SAML


(SILVER, GOLD) Стадия цикла DevOps: Manage


Раньше в качестве одной из частей включения в группу с SAML пользователям нужно было заполнять форму регистрации. В GitLab 13.7 мы представляем синхронизацию пользователей для групп с использованием SAML. Когда пользователь в первый раз входит в группу с SAML, учётная запись пользователя создаётся для него автоматически, если нет существующего пользователя с таким же адресом электронной почты. Автоматическая подготовка с SAML улучшает процесс адаптации новых пользователей и гарантирует, что вновь созданные учётные записи содержат правильную информацию.


Документация по настройке групп с SAML и оригинальный тикет.


Настраиваемый адрес электронной почты для службы поддержки


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


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


Документация по настройке адреса электронной почты для службы поддержки и оригинальный тикет.


Различайте изменения форматирования и правки, сделанные из редактора статических сайтов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Редактор статических сайтов предлагает интуитивно понятный и знакомый всем режим редактирования WYSIWYG для контента Markdown. Чтобы обеспечить единообразный формат вывода Markdown, редактор WYSIWYG автоматически переформатирует содержимое страницы в соответствии с соглашениями о стилях, определёнными в парсере Markdown. Это происходит полностью в фоновом режиме ещё до того, как вы начнёте редактировать. Однако эти изменения форматирования коммитятся вместе с вашими изменениями содержимого. Если страница, которую вы редактируете, не следовала тем же соглашениям о стилях, для проверяющих итогового мерж-реквеста может быть сложно отличить ваши изменения от автоматического форматирования.


Начиная с GitLab 13.7 редактор статических сайтов автоматически исправляет несоответствия в синтаксисе Markdown и коммитит все необходимые изменения форматирования в новой ветке. По завершении редактирования кнопка Опубликовать создаёт отдельный коммит, содержащий только ваши изменения. Это может сэкономить время проверяющим изменения, которые вместо того, чтобы продираться через изменения синтаксиса, смогут сосредоточиться на вашем контенте.


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


Документация по редактору статических сайтов и оригинальный тикет.


Предзаполненные переменные при ручном запуске конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Раньше, когда вы хотели запустить конвейер вручную, вам нужно было узнать нужные переменные, а затем ввести их на странице Запуск конвейера (Run Pipeline). Это может быть утомительно и чревато ошибками, если нужно ввести множество пар ключ-значение. Теперь форма для запуска конвейера будет сгенерирована для вашего конвейера с переменными, предварительно заполненными на основе определений переменных в вашем файле .gitlab-ci.yml, что сделает этот процесс более эффективным.


Pre-filled variables when running pipelines manually


Документация по ручному запуску конвейера и оригинальный тикет.


Собранные с помощью CI/CD пакеты всегда отображают информацию о сборке


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


Если вы публиковали пакеты в реестре пакетов, то могли заметить, что пакеты, созданные с помощью GitLab CI/CD, не всегда отображали коммит и конвейер, ответственные за создание или обновление вашего пакета. Это могло происходить по нескольким причинам.


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


В дальнейшем любой пакет, собранный или обновлённый с помощью GitLab CI/CD, будет отображать информацию о коммите и конвейере в пользовательском интерфейсе пакетов. Чтобы избежать проблем с производительностью или пользовательским интерфейсом, будут отображаться только пять обновлений пакета. В майлстоуне 13.8 мы создадим дизайн, который поможет вам легко просматривать все данные, включая историю. А пока вы можете использовать API пакетов, чтобы смотреть всю историю сборки данного пакета.


Packages built with CI/CD always display build info


Документация по реестру пакетов и сборке пакетов с помощью GitLab CI/CD и оригинальный тикет.


Используйте предопределённые переменные с прокси зависимостей


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


С помощью проксирования и кэширования образов контейнеров из Docker Hub прокси зависимостей помогает вам повысить производительность ваших конвейеров. Несмотря на то, что прокси-сервер предназначен для интенсивного использования с CI/CD, для использования этой фичи вам нужно было определить свои собственные переменные или прописать значения в вашем файле gitlab.ci-yml. Это затрудняло начало работы для тех, кто работает один, и не позволяло использовать его в качестве масштабируемого решения, особенно для организаций с множеством различных групп и проектов.


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


  • CI_DEPENDENCY_PROXY_USER: пользователь CI для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_PASSWORD: пароль для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_SERVER: сервер для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: префикс образа для извлечения образов через прокси зависимостей.

Попробуйте и дайте нам знать, что вы думаете!


Документация по аутентификации в прокси зависимостей с помощью CI/CD и оригинальный тикет.


Результаты сканирований безопасности в виджете мерж-реквеста стали удобнее


(CORE, STARTER, PREMIUM, FREE, BRONZE, SILVER) Стадия цикла DevOps: Secure


С помощью SAST и поиска секретных ключей, которые теперь доступны для всех пользователей, мы упростили жизнь всем пользователям GitLab, взаимодействующим с результатами сканирования безопасности в мерж-реквесте, за счёт облегчения доступа к результатам сканирования безопасности. Ранее результаты сканирования безопасности были доступны только на странице Обзор конвейера, и вы должны были знать, где искать, чтобы найти их там. Теперь все мерж-реквесты будут показывать, были ли для них запущены проверки безопасности, и помогут вам найти артефакты задания. Это изменение не затрагивает работу с мерж-реквестами для пользователей плана Ultimate.


Improved MR experience for security scans


Документация по просмотру результатов сканирования безопасности в мерж-реквесте и оригинальный эпик.


Специальные ссылки на уязвимости


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


Мы ввели уязвимости как полноценные объекты в 12.10. Будучи объектом, каждая из них имеет уникальный URL-адрес, позволяющий напрямую перейти к деталям любой уязвимости. Несмотря на значительное улучшение видимости и согласованности, ссылки на уязвимости в тикетах и эпиках (в русской локализации GitLab цели) всё равно нужно копировать вручную в виде ссылок Markdown. Это делает неэффективным совместное использование, а ссылки на уязвимости в других областях GitLab более громоздкими, чем для других объектов, например тикетов.


Теперь на уязвимости можно ссылаться с помощью специальных ссылок. На них впервые будет опробован новый синтаксис [object_type:ID], который в конечном итоге распространится на другие существующие ссылки. Теперь вы можете быстро вставить ссылку на уязвимость из любого места, где обычно используется специальная ссылка, например из описания тикета или мерж-реквеста. Просто введите [vulnerability:123] в описании тикета, чтобы вставить ссылку на уязвимость с идентификатором 123 в том же проекте. Вы также можете добавить к идентификатору префикс пространства имён или проекта, чтобы ссылаться на уязвимости вне контекста текущего проекта.


Документация по специальным ссылкам и оригинальный тикет.


Смотрите, какие коммиты и конвейеры выполняются в форке, а какие в родительском проекте


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


После того, как мы решили проблему, описанную в тикете 217451 в GitLab 13.3, вы получили возможность разрешать разработчикам родительского проекта создавать конвейеры для мерж-реквестов в форках. Однако не было никакого способа узнать контекст, в котором был запущен конвейер.


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


See which commits and pipelines run in the fork project vs. the parent project


Документация по запуску конвейеров в родительском проекте для мерж-реквестов из проекта-форка и оригинальный тикет.


Запросы к базе данных выполняются быстрее при использовании балансировщика нагрузки


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Доступность


Многие запросы к базе данных повторяются несколько раз, так что их можно кэшировать для повышения общей производительности. Для GitLab можно кэшировать примерно 10% всех запросов. В GitLab 13.7 мы включили кэширование запросов к базе данных, когда используется балансировка нагрузки базы данных. На GitLab.com это приводит к кэшированию ~700 000 запросов каждую минуту и сокращает среднее время выполнения запросов вплоть до 10%.


Для запросов, которые выполняются более 100 раз, мы уменьшили продолжительность запроса на 11-31% и кэшировали ~30% всех операторов SELECT, которые бы в противном случае выполнялись на реплике базы данных.


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


Для новых установок по умолчанию используется PostgreSQL 12


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


Начиная с GitLab 13.3 PostgreSQL 12 был доступен в качестве опции как для пакетов Omnibus, так и для нашего Helm chart. PostgreSQL 12 улучшает производительность, а также предлагает значительные преимущества при индексировании и секционировании.


Начиная с GitLab 13.7 новые установки GitLab будут по умолчанию использовать PostgreSQL 12. Чтобы выполнить обновление вручную, запустите gitlab-ctl pg-upgrade.


Многонодовые инстансы базы данных должны будут переключиться с repmgr на Patroni до обновления с помощью Patroni. Затем можно обновить и повторно синхронизировать вторичные ноды Geo.


Документация по настройкам баз данных в GitLab 13.3 и более поздних версиях и оригинальный тикет.




Полный текст релиза и инструкции по обновлению/установке вы можете найти в оригинальном англоязычном посте: GitLab 13.7 released with merge request reviewers and automatic rollback upon failure.


Над переводом с английского работали cattidourden, maryartkey, ainoneko и rishavant.

Подробнее..

Перевод Стать инженером DevOps в 2021 году подробное руководство

21.01.2021 12:12:35 | Автор: admin

Что касается нынешнего ИТ-рынка, среда DevOps один из лучших вариантов для ИТ-специалистов с точки зрения заработной платы и карьерного роста. И мне довольно часто задают вопрос: Как стать инженером DevOps?

В этом блоге я попытаюсь ответить на него на примере своего собственного опыта работы DevOps в различных организациях.

Многие утверждают (включая меня), что нет ничего похожего на DevOps Engineer или DevOps Team, потому что это не вещь. Однако сейчас все в отрасли уже привыкли к термину инженер DevOps, и если вы понимаете философию DevOps, эти названия не имеют большого значения.

При этом существует несколько неправильных представлений о том, что на самом деле означает этот термин. Одно из таких заблуждений DevOps это автоматизация. Но чтобы стать DevOps-инженером, недостаточно развить навыки, связанные с автоматизацией. Википедия говорит:

DevOps (обособленное сочетание разработки и эксплуатации) это культура, движение или практика, которая подчеркивает сотрудничество и общение как разработчиков программного обеспечения, так и других специалистов в области информационных технологий (ИТ) при автоматизации процесса доставки программного обеспечения и изменений инфраструктуры.

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

Вот интересный график тенденций, показывающий популярность DevOps за последние 5 лет.

Организациям, пытающимся внедрить у себя DevOps, требуются люди с навыками совместной работы, готовые изменять и внедрять новые технологии, с хорошим пониманием систем, средств автоматизации, инструментов CI/CD, систем контроля версий и сетей, с опытом использования инструментов управления проектами и т. д. Это необходимо для того, чтобы приложение было запущено на рынок без особых задержек.

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

Как стать инженером DevOps

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

В этой статье объясняется, как вам следует подготовиться к использованию инструментов и технологий для адаптации и работы в культуре DevOps.

В этой статье я рассмотрел многие темы. Новичок не может быть мастером всего. Однако наличие достаточного количества знаний в этих областях поможет вам продолжить карьеру в DevOps.

Поймите культуру DevOps

Прежде всего, необходимо понять культуру DevOps. Всё дело в объединении людей для эффективной работы над общей целью.

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

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

Как только вы начнете практиковать культуру DevOps, вы перестанете говорить, что это синоним CI/CD и автоматизации.

Узнайте больше о системах *nix

Мы живем в эпоху, когда не можем жить без систем Linux/Unix. Вы должны лучше понять и получить практические знания о различных дистрибутивах Linux, широко используемых организациями (RHEL, Centos, Ubuntu, CoreOS и т.д.).

Согласно тематическому исследованию Linux Foundation, 90 % рабочей нагрузки в публичных облаках обрабатывается на Linux.

Вот еще одно интересное исследование Redhat, в котором показаны различные дистрибутивы Linux, используемые в публичных облаках:

Теперь у вас есть достаточно причин, по которым вам стоит сосредоточиться на Linux.

Когда дело доходит до Linux, это всё про терминал, графический интерфейс менее предпочтителен в мире *nix.

Для запуска Linux-серверов вы можете использовать VirtualBox или AWS/GCP/Azure и множество других облачных платформ.

Начать изучение можно со следующего:

  • Разберитесь в процессе загрузки Linux.

  • Установите и настройте веб-серверы (Apache, Nginx, Tomcat и т.д.). И узнайте, как работают веб-серверы.

  • Узнайте, как работают процессы Linux.

  • Узнайте, как работает SSH.

  • Почитайте о различных файловых системах.

  • Изучите ведение системного журналирования, мониторинга и устранения неполадок.

  • Узнайте о важных протоколах (SSL, TLS, TCP, UDP, FTP, SFTP, SCP, SSH).

  • Научитесь управлять сервисами и попробуйте создать сервис самостоятельно (Initd, Systemd).

  • Попробуйте разместить статические и динамические сайты на веб-серверах.

  • Настройте балансировщики нагрузки и реверс-прокси (Nginx, HAproxy и т.д.).

  • Сломайте что-нибудь и научитесь устранять неполадки.

Разберитесь, как работают компоненты инфраструктуры

Основным строительным блоком любой организации является её инфраструктура. Это может быть облачный или локальный центр обработки данных. Общее понимание компонентов инфраструктуры является обязательным для человека, который хочет практиковать или работать в среде DevOps. Было бы полезно, если бы вы имели базовое представление о содержимом этого списка:

  • Сети

    • Подсеть

    • Публичная сеть

    • Частная сеть

    • Обозначения CIDR

    • Статические/динамические IP-адреса

    • Firewall

    • Прокси

    • NAT

    • Внешний и локальный DNS

    • Диагностика сети

    • VPN

  • Хранилище

    • SAN

    • Бэкапы

    • NFS

  • Отказоустойчивость(HA)

    • Кластер

    • Механизмы отказоустойчивости

    • Аварийное восстановление

  • Безопасность

    • PKI Infrastructure

    • SSL-сертификаты

  • Технология единого входа(SSO)

    • Active Directory/LDAP

  • Балансировщики нагрузки

    • Балансировка на разных уровнях модели OSI (L4, L7)

    • Алгоритмы балансировки нагрузки

    • Reverse Proxy

Могло быть и больше пунктов, но я выделил только ключевые компоненты ИТ-инфраструктуры.

Научитесь автоматизировать

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

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

  • Для среды разработки

    • Vagrant

    • Docker Desktop

    • Minikube

    • Minishift

  • Для обслуживания инфраструктуры

    • Terraform

    • CLI (соответствующего облачного провайдера)

  • Для управления конфигурацией

    • Ansible

    • Chef

    • Puppet

    • Saltstack

  • Управление образами ВМ

    • Packer

Контейнеры, распределенные системы и Service Mesh

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

Как только вы изучите Docker, можете попробовать его инструменты кластеризации и оркестрации, такие как Kubernetes, Docker Swarm и т.д. Эти платформы лучше всего подходят для архитектуры на основе микросервисов.

Вот интересная тенденция использования Kubernetes по данным Datadog:

А вот пятилетняя тенденция роста поисковых запросов по Kubernetes:

Кроме того, многие инженеры проявляют интерес к изучению Kubernetes, и в 2021 году немало людей получат сертификаты по этой технологии (CA, CKD и CKD).

Service mesh это выделенный слой инфраструктуры с низкой задержкой для обеспечения взаимодействия между сервисами. Он даёт массу возможностей для межсервисного взаимодействия: балансировки нагрузки, шифрования трафика, авторизации, трассировки, обнаружения сервисов (service discovery) и использования паттерна автоматического выключения (circuit breaker), с которым можно ознакомиться тут. Service mesh это сложная тема, когда дело касается распределенных систем. Если вы новичок в работе с инструментами для контейнеров, вы можете изучить это после получения хороших знаний об архитектуре на основе микросервисов.

Журналирование и мониторинг

Журналирование и мониторинг очень важные аспекты инфраструктуры.

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

Каждая компания будет иметь отдельный уровень инфраструктуры под журналирование. Обычно используются такие стеки, как Splunk, ELK и Graylog. Кроме того, существует несколько SaaS-компаний, таких как Loggly, которые предоставляют инфраструктуру для централизованного хранилища журналов.

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

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

Также на основании правил, настроенных в системах мониторинга, будут срабатывать оповещения. Например, оповещение может быть в виде уведомления в Slack или Telegram, задачи в Jira, простого email, SMS-сообщения или даже звонка на телефон. Все схемы оповещения могут разниться от компании к компании.

Как инженер DevOps, вы должны иметь доступ к журналам и уметь устранять неполадки во всех средах (Dev, QA, Stage, Prod). Понимание регулярных выражений очень важно для построения запросов в любом инструменте централизованного хранилища журналов.

Понимание лучших практик в сфере кибербезопасности (DevSecOps)

DevSecOps ещё одна область, связанная с интеграцией практик безопасности на каждом этапе DevOps. Википедия говорит:

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

Обзор инфобезопасности в 2020 показывает распределение разных кибератак по регионам:

В облачных средах криптомайнинг является распространенной атакой. В основном это происходит, когда секреты облачного доступа хранятся плохо, так что хакеры получают к ним доступ.

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

А вот основные стандартные практики DevSecOps, опубликованные Redhat:

Hashicorp Vault отличный инструмент для управления секретами. Существует множество рабочих процессов для управления секретами среды.

Изучайте программирование

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

Например, для написания конвейера Jenkins в декларативном виде (как код) требуется знания Groovy; кастомный модуль Ansible требует знания Python; для написания оператора Kubernetes требуется опыт работы с Go.

Обратите внимание на следующие языки программирования, которые часто используются для написания скриптов или небольших программ:

  • Bash/Shell

  • Python

  • Go

Go действительно становится популярным в сфере DevOps. Его используют многие инструменты. Например, Kubernetes и Terraform написаны на Go. JFrog исследовал внедрение Go во время GopherCon, и 18 % респондентов заявили, что используют этот язык для работы, связанной с DevOps.

Изучите Git, научитесь документировать, узнайте о GitOps

Очень важно применять систему контроля версий ко всему, что вы делаете (кроме паролей и секретов). Git лучший инструмент для этого. Для него доступно множество руководств, и изучение важных операций с Git не займет много времени.

Вы можете начать с Github или Bitbucket в качестве удаленного репозитория кода.

А как только вы поймете Git, изучите GitOps. Что этот такое?

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

Ещё очень важно документировать всё, что вы делаете. Каждый репозиторий должен иметь файл README, лучше объясняющий ваш код. Хорошая документация поможет не только вам, но и тем, кто попытается использовать вашу кодовую базу.

Освойте непрерывный жизненный цикл доставки приложений

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

  • Continuous Integration (Непрерывная интеграция)

  • Continuous Delivery (Непрерывная доставка)

  • Continuous Deployment (Непрерывное развертывание)

Научитесь использовать инструменты CI/CD, такие как Jenkins, Gitlab CI, Travis CI и т.д. Вот хорошее графическое представление процесса CI/CD:

DevOps vs SRE

SRE еще одна развивающаяся тема в сообществе DevOps. Это набор практик и философий, разработанных Google. Вот что компания говорит о DevOps и SRE:

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

Я рекомендую изучить официальные документы от Google:

  1. What is SRE?

  2. SRE vs. DevOps: competing standards or close friends?

Читать, читать и еще раз читать

Нет ничего лучше для приобретения знаний, чем чтение. Прочтите хотя бы один технический блог DevOps, связанный с инженерией. Следите за всеми значимыми инженерными блогами, такими как Netflix, Twitter, Google и т.д. Узнайте, как они используют правильный набор инструментов, стратегии развертывания и свои последние проекты с открытым исходным кодом.

Заключение

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

А теперь мне интересно услышать от вас:

Что из культуры DevOps вы применяете на практике у себя?

Каков путь становления DevOps инженером вы прошли?

В любом случае, делитесь вашими мыслями об этой статье в комментариях.

Подробнее..

Avito Android meetup работа с Gradle и проблемы при сборке проектов

01.03.2021 12:17:20 | Автор: admin

Привет, Хабр! 11 марта в 18:00 по Москве мы проведём онлайн-митап для андроид-разработчиков.

В этот раз без внешних спикеров все доклады будут от инженеров нашей платформенной команды Speed, которые отвечают за быструю доставку изменений во всех андроид-приложениях Авито до пользователей. Ребята каждый день решают задачи, связанные с CI/CD и локальной работой с проектами, так что им есть, чем поделиться.

Доклады

Как правильно писать на Gradle в 2021 Дмитрий Воронин

В Gradle есть куча способов решить одну и ту же задачу, однако часть из них оптимальнее других. Я разберу несколько распространённых ошибок и покажу, как сделать лучше.

Как защищаться от частых проблем при сборке проекта Евгений Кривобоков

На сборку проекта влияет много неочевидных настроек. Они могут привести к медленной сборке или даже ошибкам в рантайме. Как защититься от неправильной настройки проекта? Что делать, если соглашения не работают или не получается написать Android lint проверку?

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

Gradle build scan на коленке Сергей Боиштян

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

Доклад будет интересен тем, кто страдает от поиска ошибок в своём CI и developer experience инженерам, которые могут переиспользовать наше решение или идеи.

Когда закончим с докладами, можно будет неформально пообщаться в Зуме со спикерами. Ссылка появится в чате трансляции.

Пароли и явки

Трансляция на нашем ютуб-канале стартует в четверг 11 марта в 18:00 по московскому времени. На трансляции можно сразу нажать кнопку напомнить, чтобы ничего не пропустить.

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

До встречи в онлайне!

Подробнее..

XCResult как и зачем читать

04.03.2021 16:23:55 | Автор: admin


В 2018 году Apple в очередной (третий) раз обновили формат, в котором выдаётся информация о прогоне тестов. Если раньше это был plist файл, который представлял из себя большой xml, то теперь это большой файл с расширением xcresult, который открывается через Xcode и содержит в себе кучу полезной информации, начиная c результатов тестов с логами, скриншотами и заканчивая покрытием таргетов, диагностической информацией о сборке и многим другим. Большинство разработчиков не работает каждый день с этим, но инфраструктурщики в данной статье могут найти что-то полезное.

Разложим по полочкам плюсы и минусы обновления формата


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

Чем удобен новый xcresult?
Открывается нативными средствами через Xcode.
Можно передавать коллегам из QA и разработки, даже если у них нет локально проекта. Все откроется и покажет нужную информацию.
Содержит исчерпывающую информацию о прогоне тестов.
Можно читать не только через Xcode.

Вот о последнем пункте мы и будем говорить в этой статье.

Зачем читать XCResult не через Xcode?


Если у вас в компании настроены процессы CI&CD, то наверняка вы собираете метрики по сборкам проекта, по стабильности и количеству тестов, и, конечно, данные по тестовому покрытию. Скорее всего, где-нибудь на Bamboo, Jenkins, Github у вас рисуются упавшие тесты или статус CI, или процент покрытия. Такие операции принято автоматизировать и отдавать на откуп бездушным машинам. Какие инструменты есть у нас для этого?
Apple, вместе с релизом нового формата, выпустили и инструменты xcresulttool и xccov, с которыми можно работать из терминала.

Что мы можем достать, используя xccov?


xcrun xccov view --report --json /path/to/your/TestScheme.xcresult

Запрос вернёт исчерпывающую информацию о том, каким покрытием обладают все таргеты, какие методы и каких классов покрыты, сколько раз они были выполнены и какие строчки выполнялись. Объекты обладают схожей структурой. Всего там 4 уровня: корень, таргет, файл, функция. Все уровни, кроме корневого, имеют поле name. Во всех уровнях есть поля coveredLines и lineCoverage. Важно отметить, что объекты имеют какой-то собственный контекст. Всю структуру можно описать в несколько протоколов.



Помимо протоколов выделим следующие структуры: CoverageReport агрегатор всего и корень. Он содержит в себе массив объектов Target. Каждый Target содержит в себе массив File, которые, в свою очередь, содержат массив Function. Эти объекты будут реализовывать протоколы, которые описаны выше.
Нас интересует поле lineCoverage. Для составления красивого отчета (как в fastlane) обратимся к полю lineCoverage и пройдем по всем объектам нехитрой функцией:



Получим что-то похожее на:

Coverage Report Summary:

Utils.framework: 51,04 %

NavigationAssistantKit.framework: 0,0 %

NavigationKit.framework: 35,85 %

Logger.framework: 20,32 %

FTCCardData.framework: 78,21 %

FTCFeeSDK.framework: 25,25 %

ErrorPresenter.framework: 2,8 %

MTUIKit.framework: 0,24 %

AnalyticsKit.framework: 47,52 %

EdaSDK.framework: 1,18 %

Alerts.framework: 85,19 %

Resources.framework: 39,16 %

QpayApiTests.xctest: 88,37 %

FTCFeeSDKTests.xctest: 97,91 %


P.S. Для того, чтобы coverage собирался, необходимо добавить в вашу команду тестирования параметр -enableCodeCoverage YES или включить в настройках схемы в Xcode.

Какие возможности даст xcresulttool?


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

Для начала неплохо ознакомиться с самим интерфейсом:

xcrun xcresulttool --help

OVERVIEW: Xcode Result Bundle Tool (version 16015)

USAGE: xcresulttool subcommand [options] ...

SUBCOMMANDS:

export Export File or Directory from Result Bundle

formatDescription Result Bundle Format Description

get Get Result Bundle Object

graph Print Result Bundle Object Graph

merge Merge Result Bundles

metadata Result Bundle Metadata

version XCResultKit Version


Чтобы прочитать структуру, нам достаточно вызвать команду:

xcrun xcresulttool get --path /path/to/your/res.xcresult --format json

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

xcrun xcresulttool get --path /path/to/your/res.xcresult --format json --id {id}

Тогда мы получим объекты с тест-таргетами, типом тестов, которые разбиты по тест-классам и test suits с отчётами с логами, скриншотами, временем выполнения и прочей информацией по каждому тесту.
К сожалению, причину падения красных тестов не получится вытащить просто для этого придётся делать ещё один запрос на каждый упавший тест (а на самом деле даже не один! Если тест крэшнул, то крэшлоги вместе со стректрейсом лежат в другом месте и это ещё один запрос!

Для Failure Summary используется тот же запрос:

xcrun xcresulttool get --path /path/to/your/res.xcresult --format json --id {id}

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

Что делать с этими справочными знаниями дальше?


Автоматизировать, конечно же! Если вы попробуете выполнить эти команды, то увидите, что ответы гигантские и их тяжело читать. Как автоматизировать? Ruby, Python Или Swift?
Конечно же, swift. Его знает любой современный iOS разработчик. Проект открывается в Xcode, доступна отладка, подсветка синтаксиса, строгая типизация. Короче, мечта! Особенно при появлении Swift package manager.
Ни для кого не секрет, что с помощью swift мы легко можем запускать процессы, слушать ошибки и получать выходные данные. В самом простом случае мы можем обойтись такой конструкцией:



Нам остается теперь только исследовать формат XCResult через уже знакомые нам xcrun xcov и xcrun xcresulttool. Например, чтобы прочитать покрытие тестами, мы используем:



А чтоб получить оглавление XCResult нам нужно выполнить:



Но как нам получить наши заветные структуры CoverageReport и XCResult?
Получаем строку из Data, которую вернет нам первая Shell команда и помещаем содержимое сюда: quicktype.io.
Сервис сгенерирует нам что-то похожее на нужные свифтовые структуры. Правда использовать результат как есть не получится. Придётся пристальнее изучать структуру ответа и выбрасывать дубли. Тем не менее такая работа не составляет большого труда. Можно отбрасывать ненужные части, а можно заняться исследованием и выделить несколько основных кирпичиков:



На основании этого описать уже остальные структуры, например:



или даже такие сведения о компьютерах, на которых совершался прогон:



Ну а этим-то как пользоваться?


Есть два пути, как пользоваться нашим скраппером. Первый как executable, и здесь здорово помогает библиотека swift-argument-parser от Apple. До этого приходилось писать обработку аргументов самим, покрывать тестами, поддерживать. Сейчас эту работу взяла на себя популярная библиотека, меинтейнерам которой можно доверять.
Есть две команды: получить отчёт по покрытию тестами и сгенерировать junit отчёт о результатах тестирования. Нужно сбилдить проект и запускать бинарник, передавая необходимые аргументы:



Второй путь использовать этот проект как библиотеку. У нас есть большой CI проект, который отвечает за сборку, тестирование и доставку нашего продукта KoronaPay. Например, мы можем по результатам прохождения тестов извлекать все assertion failures и крэши в тестах приблизительно так:



Или получать красные тесты, анализировать флаки и перезапускать только их.
А как анализировать? Всё просто и непросто одновременно. Чтобы достать детали причины падения теста, надо сделать дополнительный запрос к xcresult по идентификатору failure summary. А затем из failure summary вытаскивать информацию. На сегодняшний момент мы научились искать крэши в тестах и lost connection случаи, а также вытаскивать причины. Понять, что произошел крэш несложно. Надо лишь найти в failureSummaries заветные слова crashed in.



Чуть сложнее вытащить причину крэша.
Здесь нам пригодится механизм рефлексии в swift, который хоть и несколько ограничен, но отлично подходит для решения этой задачи. Необходимо найти все объекты типа Attachment с именем kXCTAttachmentLegacyDiagnosticReportData.



В методе reflectProperties нет ничего магического, это простенький extension для Mirror:



Еще одна категория красных тестов ассерты. В отличие от крэшей здесь не получится просто поискать строку crashed in. Такие тесты могут маскироваться под lost connection случаи. Чтобы докопаться до причины, придется пройтись по нескольким массивам внутри объекта TestCase примерно так:



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



Вместо заключения


Как и все существующие в этой области решения, наш скраппер не является исчерпывающим инструментом для анализа xcresult. Чтобы получить всю информацию и посмотреть скриншоты, все еще надо открывать xcresult через Xcode. Однако если у вас настроен CI и вы хотите видеть результаты тестов быстро, то, скорее всего, сможете оценить связку junit и нашего xcscrapper по достоинству.
Подробнее..

Советы по работе с Gradle для Android-разработчиков

25.03.2021 12:22:32 | Автор: admin

Всем привет! Я пишу приложения под Android, в мире которого система сборки Gradle является стандартом де-факто. Я решил поделиться некоторыми советами по работе с Gradle с теми, у кого нет чёткого понимания, как правильно структурировать свои проекты и писать build-скрипты.



Часто разработчики используют Gradle по наитию и не изучают целенаправленно, потому что не всегда хватает ресурсов на инфраструктурные задачи. А если возникают какие-либо проблемы, то просто копируют готовые куски build-скриптов из ответов на Stack Overflow. Во многом проблема кроется в сложности и чрезмерной гибкости Gradle, а также в отсутствии описания лучших практик в официальной документации.


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



Небольшой оффтоп для тех, кому совсем ничего не понятно в Gradle-скриптах


Я заметил, что в Android-сообществе встречаются люди, которые могут годами разрабатывать приложения, но при этом не понимать, как работает Gradle. И достаточно продолжительное время и я был одним из них. Но однажды всё же решил, что гораздо проще потратить время на системное изучение Gradle, чем постоянно натыкаться на непонятные проблемы.


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


Теперь к советам.


#1 Не редактируйте Gradle-скрипты через IDE


Project structure


Android studio умеет генерировать стартовый проект с базовой структурой и готовыми build-скриптами, а также удалять и добавлять модули в существующем проекте. А при редактировании Gradle-скриптов IDE нам заботливо подсказывает, что можно вносить изменения в скрипты через графический интерфейс в меню "File -> Project structure...". И в начале своей карьеры я вполне успешно пользовался этим инструментом. Но у него есть существенный недостаток: IDE не запускает честную фазу конфигурации Gradle и не смотрит на то, что формируется в памяти при сборке, а всего лишь пытается как-то парсить build-скрипты. Зачастую этот инструмент не распознает то, что было написано вручную, что, на мой взгляд, перечеркивает его пользу.


Мой совет: лучше не редактировать скрипты через IDE, а использовать редактор кода.


#2 Обращайте внимание на соглашение по именованию модулей


В Gradle имя проекта (модуля) берется из соответствующего поля name в объекте Project или названия директории, в которой он лежит. В своей практике я видел разные стили именования модулей, например, в camel- или snake- кейсе: MyAwesomeModule, my_awesome_module. Но есть ли какие-то устоявшиеся соглашения об именах модулей? Кажется, официальная документация Gradle ничего нам об этом не говорит. Но нужно принять во внимание тот факт, что проекты Gradle при публикации в Maven будут соответствовать один к одному модулям Maven. И у Maven есть соглашение, что слова в названиях модулей должны разделяться через символ -. То есть правильнее будет такое название модуля: my-awesome-module.


#3 Что выбрать: Kotlin vs Groovy


Изначально в Gradle для DSL использовался язык Groovy, но впоследствии была добавлена возможность писать build-скрипты на Kotlin. Возникает вопрос: что же сейчас использовать? И однозначного ответа на него пока что нет.


Лично я за использование Kotlin, так как не очень хочу только лишь ради build-системы изучать ещё один язык Groovy. Наверно, для всего Android сообщества DSL на Kotlin существенно понижает порог вхождения в Gradle. Кроме того, у build-скриптов на Kotlin лучше поддержка в IDE с автокомплитом, но, тем не менее, она все еще далека от идеала.


В качестве минуса Kotlin я бы выделил то, что могут встретиться какие-то старые плагины, которые изначально были заточены только под Groovy, и для их подключения придется потратить больше времени.


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


#4 Как прописывать зависимости в многомодульных проектах


Возьмем небольшой пример проекта со следующей структурой:
Project structure


Основной модуль, из которого собирается apk, зависит от feature-модулей, а также в нём прописаны какие-то внешние зависимости. feature-модули, в свою очередь, содержат транзитивные зависимости, которые могут пересекаться с зависимостями в других модулях.


В чем проблема такого проекта? Здесь будет тяжело глобально обновлять зависимости в каждом из файлов. Очень легко забыть поднять версию в одном из скриптов, и тогда возникнут конфликты. По умолчанию Gradle умеет разрешать такие конфликты, выбирая максимальную версию, так что, скорее всего, сборка будет успешной (поведение можно менять через resolution strategy).


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


Java platform plugin


Разработчики Gradle предлагают для описания зависимостей создать отдельный специальный модуль, где будут описаны только зависимости с конкретными версиями. К этому модулю надо применить java platform plugin. Далее подключаем этот модуль в остальные модули и при указании каких-то внешних зависимостей не пишем конкретную версию:
Java platform plugin


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


Перейду к общепринятым в сообществе способам описания зависимостей.


Описание зависимостей в extra properties


Достаточно часто можно увидеть практику, когда строки с зависимостями хранят в extra properties корневого проекта, по сути это словарь, доступный всем дочерним модулям. Пример использования можно встретить в некоторых библиотеках от Google.


В корневом проекте описываем зависимости. Вот кусок build-скрипта из библиотеки Google, где зависимость возвращается функцией compatibility:


ext {    compileSdkVersion = 29    minSdkVersion = 14    targetSdkVersion = 29    androidXVersions = [            annotation: '1.0.1',            appCompat: '1.1.0'      // ...    ]}/** * Return the module dependency for the given compatibility library name. */def compatibility(name) {  switch (name) {    case "annotation":      return "androidx.annotation:annotation:${androidXVersions.annotation}"    case "appcompat":      return "androidx.appcompat:appcompat:${androidXVersions.appCompat}"

И обращаемся к ним из дочерних модулей:


dependencies {    api compatibility("annotation")    api compatibility("appcompat")    api compatibility("cardview")    api compatibility("coordinatorlayout")    api compatibility("constraintlayout")    api compatibility("core")    api compatibility("dynamicanimation")    // ...}

Описание зависимостей в скриптовом плагине


Описанный способ с extra properties можно немного модифицировать и вынести описание зависимостей в скриптовый плагин, чтобы не засорять корневой проект. А уже скриптовый плагин можно применить или к корневому, или ко всем дочерним проектам сразу (через allprojects {}), или к отдельным. Такой способ я тоже встречал.


Описание зависимостей в buildSrc


В buildSrc можно писать любой код, который будет компилироваться и добавляться в classpath build-скриптов. В последнее время стало популярно использовать buildSrc для описания там зависимостей. Например, в библиотеке Insetter Chris Banes так и делает.


Все, что нужно, это добавить синглтон со строками в buildSrc, и он станет виден всем модулям в проекте:


object Versions {    const val minSdk = 23    const val compileSdk = 29    const val kotlin = "1.4.20"    const val kotlinCoroutines = "1.4.0"    const val okHttp = "4.9.0"    const val retrofit = "2.9.0"    const val moshi = "1.11.0"}object Dependencies {    object Kotlin {        const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}"        const val reflect = org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlin}"    }    object Google {        const val materialComponents = "com.google.android.material:material:1.2.1"        const val googleAuth = "com.google.android.gms:play-services-auth:18.1.0"        const val location = "com.google.android.gms:play-services-location:17.1.0"        const val tasks = "com.google.android.gms:play-services-tasks:17.2.0"    }}

Использовать buildSrc для зависимостей очень удобно, так как будут статические проверки и автокомплит в IDE:


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


Композитные сборки


Можно достичь похожего результата со статическими проверками и автокомплитом, используя композитные сборки, при этом избавившись от проблемы инвалидации всего кэша. Я расскажу про него лишь кратко, а подробный гайд по миграции с buildSrc можно прочитать в статье из блога Badoo или статье от Josef Raska.


В композитных сборках мы создаем так называемые включенные сборки (included build), в которых можно писать плагины и подключать их в своих модулях. Включенные сборки описываются в файле settings.gradle.



Если мы хотим всего лишь подсунуть в classpath build-скриптов строки с зависимостями, то достаточно создать пустой плагин, а рядом с ним положить тот же файл с зависимостями, который мы использовали раньше в buildSrc:


// Build скрипт включенной сборки// ./dependencies/build.gradle.ktsplugins {    `kotlin-dsl`}repositories {    jcenter()    google()}gradlePlugin {    plugins {        register("dependencies") {            id = "dependencies"            implementationClass = com.rmr.dependencies.DependenciesPlugin        }    }}

// Плагин из включенной сборки// ./dependencies/src/main/kotlin/com/rmr/depenendencies/DependenciesPlugin.ktpackage com.rmr.dependenciesimport org.gradle.api.Pluginimport org.gradle.api.Projectclass DependenciesPlugin : Plugin<Project> {    override fun apply(target: Project) {        // Do nothing, just load dependencies to classpath    }}

Все, что осталось сделать, применить плагин к корневому проекту:


plugins{ id("dependencies") }

И мы получим практически тот же результат, как и с использованием buildSrc.


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


#5 Как обновлять зависимости


В любом активном проекте надо постоянно следить за обновлением библиотек. IDE умеет подсвечивать для каждого модуля, описанного в блоке dependencies {}, наличие новых стабильных версий в репозиториях:


New dependencies


Но этот инструмент работает только для зависимостей, описанных строковыми литералами в build-скриптах, а если мы попытаемся использовать способ с композитными сборками, buildSrc или extra properties, то IDE перестанет нам помогать. Кроме того, визуально просматривать build-скрипты в модулях, для того чтобы сделать обновление библиотек, на мой взгляд, не очень удобно.


Но есть решение использовать gradle-versions-plugin. Для этого просто применяем плагин к корневому проекту и регистрируем task для проверки новых версий зависимостей. Этот task надо настроить, передав ему лямбду для определения нестабильных версий:


fun isNonStable(version: String): Boolean {    val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.toUpperCase().contains(it) }    val regex = "^[0-9,.v-]+(-r)?$".toRegex()    val isStable = stableKeyword || regex.matches(version)    return isStable.not()}tasks.withType<DependencyUpdatesTask> {    rejectVersionIf {        isNonStable(candidate.version) && !isNonStable(currentVersion)    }}

Теперь запуск команды ./gradlew dependencyUpdates выведет список зависимостей, для которых есть новые версии:


The following dependencies have later milestone versions: - androidx.constraintlayout:constraintlayout [2.0.1 -> 2.0.4]     http://tools.android.com - androidx.core:core-ktx [1.5.0-alpha05 -> 1.5.0-beta03]     https://developer.android.com/jetpack/androidx/releases/core#1.5.0-beta03 - androidx.fragment:fragment-ktx [1.3.0-beta02 -> 1.3.1]     https://developer.android.com/jetpack/androidx/releases/fragment#1.3.1 - androidx.lifecycle:lifecycle-runtime-ktx [2.2.0 -> 2.3.0]     https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.0 - com.github.ben-manes:gradle-versions-plugin [0.36.0 -> 0.38.0] - com.github.ben-manes.versions:com.github.ben-manes.versions.gradle.plugin [0.36.0 -> 0.38.0] - com.github.bumptech.glide:glide [4.11.0 -> 4.12.0]     https://github.com/bumptech/glide

#6 Старайтесь не использовать feature-флаги в build config


Во многих проектах release, debug и другие сборки отличаются по функциональности. Например, в отладочных сборках могут быть включены какие-то логи, мониторинг сетевого трафика через прокси, debug menu для смены окружений и т.д. И часто для реализации такого используют флаги, прописанные в build config, например:


android {    buildTypes {        getByName("debug") {            buildConfigField("Boolean", "ENABLE_DEBUG_SCREEN", "true")        }        getByName("release") {            buildConfigField("Boolean", "ENABLE_DEBUG_SCREEN", "false")        }    }}

А дальше такие флаги используются в коде приложения:


if (BuildConfig.ENABLE_DEBUG_SCREEN) {} else {}

И у такого решения есть недостатки. Довольно легко перепутать значения флагов и ветки if/else: if(enabled) {} else {} или if(disabled) {} else {}. Именно так однажды, во время рефакторинга, я случайно отправил в релиз то, что должно было включаться только в сборках для QA-отдела (думаю, у многих были похожие истории). Тогда проблему обнаружили оперативно, мы перевыпустили сборку в маркет. Кроме того, недостижимый код может быть скомпилирован и попасть в релиз (здесь я не буду рассуждать о том, что мертвый код может вырезаться из итогового приложения). Ну и многим известно, что любые операторы ветвления лучше заменять полиморфизмом. И в Gradle есть статический полиморфизм.


Вместо флагов можно использовать разные source set для различных build variant ("src/release/java ...", "src/debug/java ..."). А если такой код хочется вынести в отдельные модули, то можно использовать специальные конфигурации: debugImplementation, releaseImplementation и т.д. Тогда мы сможем написать код с одним и тем же интерфейсом, но разной реализацией для различных типов сборок.


Например, мы можем выделить debug menu в отдельный модуль и подключать его только для debug и QA-сборок:


dependencies {    val qaImplementation by configurations    debugImplementation(project(":feature-debug-screen"))    qaImplementation(project(":feature-debug-screen"))}

А stub реализацию для релизной сборки можно реализовать через source set.


#7 Несколько слов про базовую структуру проекта


Совет немного не по теме, но я решил добавить его как часть своего опыта, так как модуляризация напрямую связана с Gradle.


Если для крупных проектов модуляризация кажется вполне очевидным решением, то не совсем понятно, как стоит поступать при старте небольших проектов или когда невозможно предсказать дальнейшее развитие кодовой базы продукта. Нужно ли выделять какие-то модули или достаточно начать с монолита? Я бы, помимо app модуля с основным приложением, всегда выделял как минимум два отдельных модуля:


  • UI kit: стили, кастомные элементы управления, виджеты и т.д. Обычно элементы управления на всех экранах приложения делаются консистентно в одном стиле (а возможно, у вас целая дизайн-система), и если в какой-то момент захочется выделить feature-модуль, то он также будет опираться на единый UI kit. Заранее подготовленный модуль с элементами управления и стилями упростит задачу и не потребует значительного рефакторинга приложения.
  • Common / utils: все утилитные классы и любые решения, которые не только потребуются в нескольких модулях, но и могут даже копироваться из проекта в проект. Особенно в контексте аутсорса такой модуль будет удобным при старте новых проектов. При вынесении классов в отдельный модуль, а не пакет, можно быть уверенным, что в его коде не окажется каких-либо бизнес сущностей конкретного приложения. Потенциально такой модуль может стать полноценной библиотекой, опубликованной в репозиторий.

#8 Не забывайте про matchingFallbacks


Часто, помимо debug и release, мы создаем и другие типы сборок, например, qa для тестов. И при создании модулей в приложении необязательно их прописывать в каждом build-скрипте. Достаточно при создании своего build type указать в модуле основного приложения те build type, которые следует выбирать при отсутствии каких-то конкретных:


android {    buildTypes {        create("qa") {            setMatchingFallbacks("debug", "release") // если не найдется qa, то искать сначала debug, затем release        }    }}

#9 Убирайте ненужные build variant


Build variant формируются из всех возможных сочетаний product flavor и build type. Возьмем небольшой синтетический пример: создадим три build type debug (отладочная сборка), release (сборка в маркет) и qa (сборка для тестирования), а во flavor вынесем разные сервера, на которые может смотреть сборка, production и staging (тестовое окружение). Возможные build variant будут выглядеть так:
Build variants


Очевидно, что сборка в маркет, которая будет смотреть на тестовое окружение, совершенно бессмысленна и не нужна (stagingRelease). И чтобы исключить ее, можно добавить variant filter:


android {    variantFilter {        if (name == "stagingRelease") {            setIgnore(true)        }    }}

#10 В некоторых модулях, завязанных на Android Framework, можно не использовать Android Gradle Plugin


Если какой-то из ваших модулей завязан на классы из Android Framework, то вовсе не обязательно сразу применять к нему Android Gradle Plugin и писать там файл манифеста. Модули с AGP более тяжеловесные, чем чистые java/kotlin модули, так как при сборке будут объединяться манифесты, ресурсы и т.д. Когда вам всего лишь требуется для компиляции модуля что-то вроде классов Activity, Context и т.д., то можно просто добавить Android Framework как зависимость:


dependencies {    compileOnly("com.google.android:android:4.1.1.4")}

#11 Как написать Gradle-плагин для CI на примере gitlab


Настройка CI отдельная большая тема, которая потянет на целую увесистую статью. Но я решил немного коснуться её и рассказать, как при помощи написания Gradle-плагина настроить версионирование сборок. Возможно, этот совет поможет тем, кто только поднимает CI, но не знает, как лучше это сделать.


Задача сделать так, чтобы в сборках на CI versionCode ставился автоматически и представлял из себя последовательные номера 1, 2, 3 и т.д. Я встречал в своей практике, когда в качестве versionCode брался CI job id или каким-то образом использовался timestamp. В таких случаях versionCode с каждой новой версией повышался и был уникальным, но семантически такие версии выглядели достаточно странно.


Основная идея проста нужно хранить номер будущего релиза где-то во внешнем источнике, куда имеет доступ только сборка, выполняемая на CI. А после каждой успешной публикации нужно инкрементировать этот номер и перезаписывать (нам важно, чтобы сборка не просто успешно выполнилась, но и полученные артефакты распространились для тестировщиков). Стоит оговориться, что такое решение не позволит корректно делать одновременно несколько сборок. Всю эту логику достаточно просто оформить в Gradle-плагин. Как мы уже выяснили, плагины лучше писать, используя композитные сборки.


В случае использования Gitlab CI подставляемый versionCode можно хранить в переменной окружения Gitlab. В его API есть метод для обновления переменных окружения: PUT /projects/:id/variables/:key. Для авторизации используем или project access token, или personal access token для старых версий gitlab.


Расписал добавление такого плагина по шагам, чтобы показать, насколько это просто.


Шаг 1: в настройках проекта на gitlab создать переменные окружения


Нам понадобятся переменные VERSION_CODE_NEXT для хранения номера версии и токен для доступа к API gitlab:


Шаг 2: создать композитную сборку


Добавим в корне проекта директорию ./includedBuilds/ci, а в ней файл build.gradle.kts:


plugins {    `kotlin-dsl`}kotlinDslPluginOptions {    experimentalWarning.set(false)}repositories {    jcenter()    google()}dependencies {    implementation("com.squareup.okhttp3:okhttp:4.9.0")}gradlePlugin {    plugins {        register("gitlab-ci") {            id = "gitlab-ci"            implementationClass = "com.redmadrobot.app.ci.CIPlugin" // Этот плагин создадим в следующих шагах        }    }}

Рядом создадим пустой файл ./includedBuilds/ci/settings.gradle.kts, если этого не сделать, то у вас сломается clean проекта.


В корневом проекте в файл settings.gradle.kts добавим строку includeBuild("includedBuilds/ci").


Шаг 3: написать плагин


Так будет выглядеть метод для получения versionCode, его можно будет использовать в build-скрипте (можно добавить в любой файл: при применении плагина код будет скомпилирован и добавлен в classpath build-скрипта):


const val GITLAB_VARIABLE_NEXT_VERSION = "VERSION_CODE_NEXT"private const val DEFAULT_VERSION_CODE = 1fun getVersionCode(): Int = if (isRunningOnCi()) {    getNextVersionCode()} else {    DEFAULT_VERSION_CODE}private fun isRunningOnCi(): Boolean = System.getenv()["CI"] != nullprivate fun getNextVersionCode(): Int {    return System.getenv()[GITLAB_VARIABLE_NEXT_VERSION]?.toInt()        ?: error("$GITLAB_VARIABLE_NEXT_VERSION must be specified")}

Примерно так можно написать метод для обновления переменной на gitlab:


fun updateGitlabVariable(variable: String, value: String) {    val projectId = System.getenv()["CI_PROJECT_ID"]    val accessToken = System.getenv()["TOKEN_FOR_GITLAB_API"]    val client = OkHttpClient()    val body = MultipartBody.Builder()        .setType(MultipartBody.FORM)        .addFormDataPart("value", value)        .build()    val request = Request.Builder()        .header("PRIVATE-TOKEN", accessToken)        .url("https://gitlab.com/api/v4/projects/$projectId/variables/$variable")        .method("PUT", body)        .build()    client.newCall(request).execute().use { response ->        if (!response.isSuccessful) throw IOException("Couldn't update variable)    }}

Далее пишем task, который при выполнении будет инкрементировать версию:


open class IncrementVersionCode : DefaultTask() {    @TaskAction    fun action() {        val nextVersionCode = getDistributionVersionCode() + 1        updateGitlabVariable(            GITLAB_VARIABLE_NEXT_VERSION,            nextVersionCode.toString()        )    }}

И напишем плагин, который добавит task в проект:


package com.redmadrobot.app.ciimport org.gradle.api.Pluginimport org.gradle.api.Projectclass CIPlugin : Plugin<Project> {    override fun apply(target: Project) {        target.tasks.register("incrementVersionCode", IncrementVersionCode::class.java)    }}

Шаг 4: подключить плагин


В build-скрипте проекта, из которого собирается apk, добавим следующие строки:


plugins {    id("gitlab-ci")}android {    defaultConfig {        versionCode = com.redmadrobot.app.ci.getVersionCode()    }}project.afterEvaluate {    tasks["incrementVersionCode"].mustRunAfter( // Обновление должно происходить только после публикации сборки в Firebase App Distribution        tasks["appDistributionUploadRelease"],        tasks["appDistributionUploadQa"]    )}

Теперь команда ./gradlew assembleRelease appDistributionUploadRelease incrementVersionCode будет делать новую сборку, публиковать ее и инкрементировать версию. Остается добавить эту команду на нужный триггер в ваш скрипт в .gitlab-ci.yml.


В заключение


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


Что ещё посмотреть


Мне очень помогли доклады про работу с Gradle, которые делал Степан Гончаров в разные годы. Ссылки на них, если кому-то интересна эта тема:



И в формате дискуссии: Разбор доклада Степана Гончарова Gradle от А до Я

Подробнее..

Идеальный пайплайн в вакууме

03.06.2021 22:22:36 | Автор: admin
Даже не зовите меня, если ваш pipeline не похож на это.Даже не зовите меня, если ваш pipeline не похож на это.

На собеседованиях на позицию, предполагающую понимание DevOps, я люблю задавать кандидатам такой вопрос (а иногда его еще задают и мне):

Каким, по вашему мнению, должен быть идеальный пайплайн от коммита до продашкена?/Опишите идеальный CI/CD / etc

Сегодня я хочу рассказать про своё видение идеального пайплайна. Материал ориентирован на людей, имеющих опыт в построении CI/CD или стремящихся его получить.

Почему это важно?

  1. Вопрос об идеальном пайплайне хорош тем, что он не содержит точного ответа.

  2. Кандидат начинает рассуждать, а в крутых специалистах ценится именно умение думать.

  3. Когда в вопрос добавляется такое абсолютное прилагательное, как "идеальный", то мы сразу развязываем кандидатам руки в просторе для творчества и фантазий. У соискателей появляется возможность показать, какие улучшения они видят (или не видят) в текущей работе, и что хотели бы добавить сами. Также мы можем узнать, есть ли у нашего предполагаемого будущего коллеги мотивация к улучшениям процессов, ведь концепция "работает не трогай" не про динамичный мир DevOps.

  4. Организационная проверка. Позволяет узнать, насколько широка картина мира у соискателя. Условно: от создания задачи в Jira до настроек ноды в production. Сюда же можно добавить понимание стратегий gitflow, gitlabFlow, githubFlow.

Итак, прежде чем перейти к построению какого-либо процесса CI, необходимо определиться, а какие шаги нам доступны?

Что можно делать в CI?

  • сканить код;

  • билдить код;

  • тестить код;

  • деплоить приложение;

  • тестить приложение;

  • делать Merge;

  • просить других людей подтверждать MR через code review.

Рассмотрим подробнее каждый пункт.

Code scanning

На этой стадии основная мысль никому нельзя верить.

Даже если Вася Senior/Lead Backend Developer. Несмотря на то, что Вася хороший человек/друг/товарищ и кум. Человеческий фактор, это все еще человеческий фактор.

Необходимо просканировать код на:

  • соотвествие общему гайдлайну;

  • уязвимости;

  • качество.

Мне нужны твои уязвимости, сапоги и мотоциклМне нужны твои уязвимости, сапоги и мотоцикл

Задачи на этой стадии следует выполнять параллельно.

И триггерить только если меняются исходные файлы, или только если было событие git push.

Пример для gitlab-ci

stages:  - code-scanning.code-scanning: only: [pushes] stage: code-scanning 

Linters

Линтеры это прекрасная вещь! Про них уже написано много статей. Подробнее можно почитать в материале "Холиварный рассказ про линтеры".

Самая важная задача линтеров приводить код к единообразию.

После внедрения этой штучки разработчики начнут вас любить. Потому что они наконец-то начнут понимать друг друга. Или ненавидеть, решив, что вы вставляете им палки в колеса линтеры в CI. Это уже зависит от ваших soft skills, культуры и обмена знаниями.

Инструменты

Инструмент

Особенности

eslint

JavaScript

pylint

Python

golint

Golang

hadolint

Dockerfile

kubeval

Kubernetes manifest

shellcheck

Bash

gixy

nginx config

etc

Code Quality

code quality этими инструментами могут быть как продвинутые линтеры, так и совмещающие в себе всякие ML-модели на поиск слабых мест в коде: утечек памяти, небезопасных методов, уязвимостей зависимостей и т.д, перетягивая на себя еще code security компетенции.

Инструменты

Инструмент

Особенности

Price

SonarQube

Поиск ошибок и слабых мест в коде

От 120

CodeQL

Github native, поиск CVE уязвимостей

OpenSource free

etc

Code Security

Но существуют также и отдельные инструменты, заточенные только для code security. Они призваны:

  1. Бороться с утечкой паролей/ключей/сертификатов.

  2. Cканировать на известные уязвимости.

Неважно, насколько большая компания, люди в ней работают одинаковые. Если разработчик "ходит" в production через сертификат, то для своего удобства разработчик добавит его в git. Поэтому придется потратить время, чтобы объяснить, что сертификат должен храниться в vault, а не в git

Инструменты

Инструмент

Особенности

Price

gitleaks

Используется в Gitlab Security, может сканить промежуток от коммита "А" до коммита "Б".

Free

shhgit

Запустили недавно Enterpise Edition.

От $336

etc

Сканер уязвимостей необходимо запускать регулярно, так как новые уязвимости имеют свойство со временем ВНЕЗАПНО обнаруживаться.

Да-да, прямо как Испанская Инквизиция!Да-да, прямо как Испанская Инквизиция!

Code Coverage

Ну и конечно, после тестирования, нужно узнать code coverage.

Процент исходного кода программы, который был выполнен в процессе тестирования.

Инструменты

Инструмент

Особенности

Price

go cover

Для Golang. Уже встроен в Golang.

Free

cobertura

Работает на основе jcoverage. Java мир

Free

codecov

Старая добрая классика

Free до 5 пользователей

etc

Unit test

Модульные тесты имеют тенденцию перетекать в инструменты code quality, которые умеют в юнит тесты.

Инструменты

Инструмент

Особенности

phpunit

PHP (My mom says I am special)

junit

Java (многие инстурменты поддерживают вывод в формате junit)

etc

Build

Этап для сборки artifacts/packages/images и т.д. Здесь уже можно задуматься о том, каким будет стратегия версионирования всего приложения.

За модель версионирования вы можете выбрать:

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

Инструменты для сборки образов

Инструмент

Особенности

docker build

Почти все знают только это.

buildx / buildkit

Проект Moby предоставил свою реализацию. Поставляется вместе с докером, включается опцией DOCKER_BUILDKIT=1.

kaniko

Инструмент от Google, позволяет собирать в юзерспейсе, то есть без докер-демона.

werf

Разработка коллег из Флант'а. Внутри stapel. All-in-one: умеет не только билдить, но и деплоить.

buildah

Open Container Initiative, Podman.

etc

Итак, сборка прошла успешно идем дальше.

Scan package

Пакет/образ собрали. Теперь нужно просканировать его на уязвимости. Современные registry уже содержат инструментарий для этого.

Инструменты

Инструмент

Особенности

Цена

harbor

Docker Registry, ChartMuseum, Robot-users.

Free

nexus

Есть все в том числе и Docker.

Free и pro

artifactory

Комбайн, чего в нем только нет.

Free и pro

etc

Deploy

Стадия для развертывания приложения в различных окружениях.

Деплоим контейнер в прод, как можем.Деплоим контейнер в прод, как можем.

Не все окружения хорошо сочетаются со стратегиями развертывания.

  • rolling классика;

  • recreate все что угодно, но не production;

  • blue/green в 90% процентов случаев этот способ применим только к production окружениям;

  • canary в 99% процентов случаев этот способ применим только к production окружениям.

Stateful

Нужно еще помнить, что даже имея одинаковый код в stage и production, production может развалиться именно из-за того, что stateful у них разный. Миграции могут отлично пройти на пустой базе, но появившись на проде, сломать зеленые кружочки/галочки в пайплайне. Поэтому для stage/pre-production следует предоставлять обезличенный бэкап основной базы.

И не забудьте придумать способ откатывания ваших релизов на последний/конкретный релиз.

Инструменты

Инструмент

Особенности

helmwave

Docker-compose для helm. Наша разработка.

helm

Собираем ямлики в одном месте.

argoCD

"Клуб любителей пощекотать GitOps".

werf.io

Было выше.

kubectl / kustomize

Для тех, кто любит сам придумывать шаблонизацию.

etc

На правах рекламы скажу что helmwav'у очень не хватает ваших звезд на GitHub. Первая публикация про helmwave.

Integration testing

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

Инструменты

Инструмент

Особенности

Selenium

Можно запустить в кубере.

Selenoid

Беды с образами. Требует Docker-in-Docker.

etc

Performance testing (load/stress testing)

Данный вид тестирования имеет смысл проводить на stage/pre-production окружениях. С тем условием, что ресурсные мощности на нем такие же, как в production.

Инструменты, чтобы дать нагрузку

Инструмент

Особенности

wrk

Отличный молоток. Но не пытайтесь прибить им все подряд.

k6.io

Cтильно-модно-JavaScript! Используется в AutoDevOps.

Artillery.io

Снова JS. Сравнение с k6

jmeter

OldSchool.

yandex-tank

Перестаньте дудосить конурентов.

etc

Инструменты, чтобы оценить работу сервиса

Инструмент

Особенности

sitespeed.io

Внутри: coach, browserTime, compare, PageXray.

Lighthouse

Тулза от Google. Красиво, можешь показать это своему менеджеру. Он будет в восторге. Жаль, только собаки не пляшут.

etc

Code Review / Approved

Одним из важнейших этапов являются Merge Request. Именно в них могут производиться отдельные действия в pipeline перед слиянием, а также назначаться группы лиц, требующих одобрения перед cлиянием.

Список команд/ролей:

  • QA;

  • Security;

  • Tech leads;

  • Release managers;

  • Maintainers;

  • DevOps;

  • etc.

Очевидно, что созывать весь консилиум перед каждым MR не нужно, каждая команда должна появится в свой определённый момент MR:

  • вызывать безопасников имеет смысл только перед сливанием в production;

  • QA перед release ветками;

  • DevOps'ов беспокоить, только если затрагиваются их компетенции: изменения в helm-charts / pipeline / конфигурации сервера / etc.

Developing flow

Чаще всего каждая компания, а то и каждый проект в компании, решает изобрести свой велосипед-флоу. Что после нескольких итераций приходит к чему-то, что может напоминать gitflow, gitlabFlow, githubFlow или все сразу.

Это и не хорошо, и не плохо это специфика проекта. Есть мнения, что gitflow не торт. GithubFlow для относительно маленьких команд. А про gitlabFlow мне нечего добавить, но есть наблюдение, что его не очень любят продакты - за то, что нельзя отслеживать feature-ветки.

Если вкратце, то:

  • Gitflow: feature -> develop -> release-vX.X.X -> master (aka main) -> tag;

  • GitHubFlow: branch -> master (aka main);

  • GitLabFlow: environmental branches.

TL;DR

Общий концепт

_

Feature-ветка

Pre-Production -> Production

P.S.

Если я где-то опечатался, упустил важную деталь или, по вашему мнению, пайплайн недостаточно идеальный, напишите об этом мне сделаю update.

Разработчик создал ветку и запушил в нее код. Что дальше?

Оставляйте варианты ваших сценариев в комментариях.

Подробнее..

XUnit тестирование в TeamCity

15.01.2021 14:04:54 | Автор: admin

Microsoft активно развивает свои проекты с открытым кодом, например, ASP.NET Core или MSBuild. Вместе с этим набирает популярность и тестовый фреймворк xUnit, используемый в них для модульного тестирования. В этой статье мы рассмотрим несколько способов запуска xUnit-тестов для непрерывной интеграции проекта средствами TeamCity.


Примеры конфигураций сборки можно найти на этом демо-сервере TeamCity, а исходный код лежит в этом репозитории: Lib это код тестируемого приложения, а Lib.Tests проект с тестами. Оба этих проекта нацелены на .NET версий net472 и netcoreapp2.1.


Для поддержки xUnit, в тестовом проекте задана NuGet-зависимость на соответствующий пакет xunit:


<PackageReference Include="xunit"/>


Этот мета-пакет не содержит бинарных файлов, а добавляет несколько зависимостей на NuGet-пакеты xunit.core, xunit.assert и xunit.analyzers. Это тестовое API xUnit. Каждый тестовый метод в xUnit помечается атрибутом [Fact] для обычных тестов или [Theory] для параметризованных тестов. Обычно, каждому тестируемому модулю соответствует свой тестовый класс с набором тестовых методов, проверяющих ту или иную логику. Каждому тестируемому проекту соответствует свой тестовый проект.


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


xUnit console runner


В простейшем случае, выполнить тесты можно утилитой xunit.console, из пакета xunit.runner.console. Формат запуска тестов типичен для подобных инструментов: набор тестовых сборок, фильтры для тестов, формат отчета и прочее. Кажущаяся простота использования этого подхода скрывает несколько нюансов:


  1. Где взять xunit.console на агенте TeamCity, чтобы потом использовать его для запуска тестов?
  2. Какую версию xunit.console выбрать? Пакет xunit.runner.console содержит набор исполняемых файлов для разных версий .NET.
  3. Как быть, если нужно выполнить тесты в нескольких сборках одного тестового проекта, созданных для разных версий .NET?
  4. Как настроить сбор статистики покрытия кода? Эта статистика, конечно, не может полностью отражать качество модульного тестирования, но она может быть полезной для обнаружения кода, непокрытого тестами.
  5. Какие параметры использовать для тестовой утилиты и для сбора статистики покрытия кода?
  6. Как передать результаты тестов и статистику покрытия в TeamCity?

Рассмотрим пример конфигурации сборки TeamCity, содержащей 5 шагов, в каждом из которых мы используем ранер .NET:


image


Первым шагом решаем вопрос (1): Где взять xunit.console?:


image


Этот шаг использует команду .NET, чтобы добавить зависимость на пакет xunit.runner.console в тестовый проект Lib.Tests. При восстановлении зависимости на шаге 2 утилита xunit.console появится на агенте TeamCity. Если есть несколько тестовых проектов, то зависимость можно будет добавить только в один. Но как определить точный путь к xunit.console после его загрузки? Если ничего не предпринять, пакет будет загружен в стандартную директорию кэша NuGet-пакетов:

  • в Windows: %userprofile%\.nuget\packages
  • на Mac/Linux: ~/.nuget/packages

Эти пути известны, но они зависят от операционной системы, от аккаунта, под которым запущен агент TeamCity, и от персональных настроек среды окружения для этого аккаунта. Условия могут меняться от агента к агенту. Чтобы быть уверенным, по какому пути найдется xunit.console, лучше задать переменную среды окружения NUGET_PACKAGES со значением %teamcity.build.checkoutDir%/packages. Эта переменная определяет, где появятся NuGet-пакеты после восстановления зависимостей на следующем шаге сборки. В этом примере она указывает на произвольную директорию packages, относительно корневой директории проекта. Вот как это выглядит на странице редактирования параметров:


image


Благодаря этой переменной окружения, путь к xunit.console больше не зависит от внешних факторов. Следующий шаг довольно прост. Он строит решение (solution), восстанавливая зависимости:


image


После его выполнения, в директорию packages добавятся NuGet-пакеты всех зависимостей, включая xunit.runner.console, а в директорию Lib.Tests/bin/Debug тестовые сборки, соответствующие целевым версиям .NET. И если версия тестовой сборки в директории Lib.Tests/bin/Debug/net472 уже готова для выполнения тестов, то директория Lib.Tests/bin/Debug/netcoreapp2.1 для .NET CoreApp 2.1 не содержит всех требуемых бинарных зависимостей. Вместо этого, в ней присутствуют _JSON-_файлы с описанием того, где найти эти бинарные зависимости. Шаг 3 собирает всё вместе для приложений .NET CoreApp 2.1:


image


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


  • Lib.Tests/bin/Debug/net472
  • Lib.Tests/bin/Debug/netcoreapp2.1/publish

Необходимые для запуска тестов утилиты xunit.console соответственно находятся в:


  • packages/xunit.runner.console/**/net472/xunit.console.exe
  • packages/xunit.runner.console/**/netcoreapp1.0/xunit.console.dll

где ** версия пакета xunit.runner.console.


Вопросы (1) и (2) решены. Для решения вопроса (3) необходимо добавить два шага, выполняющих тесты для двух версии .NET. Потенциально, количество целевых версий тестовых проектов .NET может быть довольно большим, поэтому и шагов тестирования с похожим набором параметров тоже может быть много. Эту проблему можно решить, например, с помощью PowerShell-скрипта или TeamCity Kotlin DSL. С вопросами (4) и (5), в общем случае, приходится разбираться самостоятельно, но, использовав команду .NET, мы получим следующие преимущества:

  • статистику покрытия кода с передачей параметров, кроссплатформенностью и всеми отчетами
  • автоматический запуск xunit.console.dll и _xunit.console.exe _подходящим способом, в зависимости от выбранного окружения (ОС, Docker, и т.д.)

Следующие два шага выполняют тесты командой .NET:

image


image


Открытым остался последний вопрос (6): Как передать результаты тестов TeamCity?. xunit.console делает это самостоятельно, полагаясь на переменную среды окружения _TEAMCITY_PROJECTNAME, которую агент TeamCity автоматически добавляет ко всем порожденным процессам. xunit.console передает результаты тестов, используя TeamCity service messages.


Хотя все вопросы и решены, но было бы здорово, если бы настройка тестов не занимала столько времени и усилий. В какой-то момент энтузиасты попытались уменьшить количество шагов конфигурации, используя механизм TeamCity Meta-Runner.


Meta-Runners Power Pack


Пакет TeamCity мета-ранеров Power Pack содержит мета-ранер xUnit.net-dotCover, который упрощает запуск xUnit-тестов и сбор статистики покрытия кода. Пример конфигурации сборки с его использованием содержит всего два шага:


image


Здесь первый шаг идентичен шагу (2) из предыдущего подхода. Второй шаг, на основе мета-ранера, запускает тесты и выглядит внушительно:


image


Этот шаг получает xunit.console из того же NuGet-пакета xunit.runner.console и запускает тесты сборок только для полных версий .NET Framework (в нашем случае .NET Framework 4.72), попутно собирая статистику покрытия кода. Он заменяет 2 шага скачивания xunit.console и запуска тестов по сравнению с предыдущим подходом.


Недостатки мета-ранера xUnit.net-dotCover:


  • Не может запускать тесты в тестовых проектах, собранных для .NET Core и .NET 5+.
  • Пользовательский интерфейс для передачи параметров dotCover не очень нагляден.
  • Нужно самостоятельно выбирать версию xunit.console в поле Xunit Runner Executable.

Очевидно, что мета-ранер не подходит для нашего случая, но, тем не менее, является рабочим решением для тестовых проектов, нацеленных на полные версии .NET Framework.


dotnet test


.NET Runner с командой test является самым простым, надежным и мощным способом тестировать .NET код в TeamCity. Наша задача решается всего лишь одним простым шагом конфигурации:


image


Такой подход имеет следующие преимущества:


  • Он не зависит от фреймворков тестирования: xUnit, NUint и других. Можно использовать и несколько одновременно.


  • Тесты могут выполняться для всех тестовых сборок решения или нескольких решений, для одного или нескольких проектов.


  • Можно запускать тесты для определенной версии .NET или для набора версий в многоцелевых проектах с использованием элемента TargetFrameworks, включая Full .NET Framework, .NET Core и .NET 5+.


  • Поддерживается тестирование в Docker-контейнерах.


  • Кросс-платформенный сбор статистики покрытия кода.



Если тестовый проект создан в средах разработки Visual Studio или Rider или с использованием шаблонов из командной строки dotnet new, например, dotnet new xunit -o Lib.Tests, то ничего дополнительного делать не нужно. Если же тестовый проект создается в "блокноте", то, помимо зависимости xunit, дополнительно нужно добавить зависимость на пакет Microsoft.NET.Test.Sdk и на тестовый адаптер xunit.runner.visualstudio:


<PackageReference Include="Microsoft.NET.Test.Sdk"/>


<PackageReference Include="xunit.runner.visualstudio"/>


Пакет Microsoft.NET.Test.Sdk содержит набор свойств и скриптов MSBuild, которые делают проект тестовым, а тестовый адаптер отвечает за интеграцию определенного тестового фреймворка: в нашем случае xunit.runner.visualstudio, с Visual Studio Test Platform. Другие фреймворки также имеют свои адаптеры, например, NUnit NUnit3TestAdapter, а MSTest MSTest.TestAdapter.


Мы рекомендуем использовать именно этот подход для тестирования вместе с xUnit и другими тестовыми фреймворками.


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

Подробнее..

CICD для Dynamics CRM на базе Azure DevOps

11.02.2021 18:04:31 | Автор: admin

image


В прошлом году на митапе "Dynamics 365 & Power Platform meetup Moscow 25 февраля 2020" я рассказывал про то как мы выстроили пайплайн непрерывной поставки CI/CD на базе GitLab CI для Microsoft Dynamics CRM.


В этой статье я расскажу и покажу как построить CI-часть пайплайна непрерывной поставки расширения функциональности Microsoft Dynamics CRM на базе Azure DevOps.


Я давно уже не заглядывал в Azure и на новогодних праздниках наконец-то появилось время в нем "поковыряться". :-) Соответственно, ничего сложного в данной статье я описывать не буду и если у вас уже есть построенный пайплайн в Azure DevOps то вы, скорее всего, ничего нового здесь не найдете. Однако, если вы чувствуете потребность в автоматизации выноса но не знаете с чего начать то эта статья как раз для вас.


Я буду использовать облачный сервис Azure DevOps Service т.к. развернуть локально и настроить не успел но, локально должно работать точно также. Начинается все, естественно, с репозитория. Для Azure Devops Pipelines можно использовать разные репозитории, Azure Repos Git, Bitbucket Cloud, GitHub, просто Git и Subversion но я, для удобства, остановлюсь на Azure Repos Git чтобы все было в одном проекте который я оставлю в публичном доступе здесь https://dev.azure.com/ZhukoffPublic/CRMCICD/.


Microsoft Dynamics CRM это CRM система на базе технологий ASP.NET, которое теперь входит в семейство Dynamics 365, которую можно расширять путем написания плагинов на C# для бэковой части и JScript для фронтальной.

Для демонстрационных целей я создал 4 проекта (вы их можете клонировать из моего репозитория):


  • Plugins плагины CRM. В нашем случае плагином который переопределяет формирование полного имени.
  • Plugins.Tests юнит-тесты для плагинов.
  • Solution кастомизации CRM. В нашем случае это сущность Контакт и основная форма для него.
  • WebResources вебресурсы CRM. В нашем случае это скрипт на форме Контакта который выводит нотификацию если не заполнен телефон.

Таким образом мы покроем основные элементы расширения MS Dynamics CRM.


Для автоматизации я буду использовать SparkleXrm написанный небезызвестным Scott Durow. Описание возможностей можно почитать здесь Simple, No fuss, Dynamics 365 Deployment Task Runner как пользовать можно посмотреть на его канале в YouTube. Также у него есть видеокурс на PaktPub Designing and Building Custom Apps using Dynamics 365 где он подробнейшим образом рассказывает что и как использовать и даже описывает как создать пайплайн на тот момент это был еще VSTS. Я выбрал spkl потому что он уже написан и сам проект в открытом доступе на GitHub, что позволяет сделать доработки самому если что-то не устраивает. Это вариант, конечно, не без недостатков, о них я расскажу позже.


Будем считать, что проект у нас есть и что он, конечно, собирается и деплоится из командной строки с помощью spkl. У меня это виртуальная машина установленной MS CRM 365 (9.0), Visual Studio, SDK, XRMToolBox и пр., короче, все в одном.


Сам пайплайн делится на две основные части, CI непрерывная интеграция (Continuous Integration) т.е. когда код непрерывно интегрируется в ветке репозитория и CD которая может быть реализована как непрерывная поставка (Continuous Delivery) или непрерывное развертывание (Continuous Deployment).


Мы начнем, конечно, с CI и думать сейчас как делать CD вовсе необязательно.


CI/CD Pipeline


Подготовительные работы


Создаем проект CRMCICD в Azure DevOps.



Клонируем репозиторий и заливаем наш проект.



Теперь создадим сам пайплайн, для этого нам нужно перейти в секцию Pipelines, жмем Create Pipeline, выбираем репозиторий Azure Repos Git далее выбираем наш репозиторий CRMCICD далее выбираем Starter Pipeline и получаем следующую картину.



Это и есть пайплайн, YAML код в файле azure-pipelines.yml который исполняется агентом в каком-то окружении, windows или linux например. Он должен состоять минимум из трех секций:


  • trigger: триггер для запуска пайплайна, в данном случае это -main, т.е. по коммиту в ветку main.
  • pool: окружение где будет выполняться пайплайн, в данном случае образ ubuntu в облаке Azure.
  • steps: сами действия которые должны быть выполнены.

Если сохранить пайплайн в таком виде то он будет запускаться на каждый коммит в ветку main. Поэтому ставим trigger: none и сохраняем так пока его не настроим и не отладим.


Наш CI будет состоять из 2 этапов:


  • Сборка проекта и решения
  • Развертывание на локальную среду

2-й шаг не обязателен но я его добавил чтобы был пример развертывания на локальную среду с помощью spkl, полезно сразу получить то, что только что залили в main ветку.


Сборка проекта и решения


Первым делом меняем агента на windows т.к. linux нас никак не устроит.
vmImage: 'windows-latest'


Добавляем переменные для удобства.


variables:  solution: '**/*.sln'  buildPlatform: 'Any CPU'  buildConfiguration: 'Debug'

Добавляем следующие шаги:


steps:# Установка NuGet- task: NuGetToolInstaller@1  displayName: 'Install NuGet tool'# Восстановление пакетов NuGet для проекта- task: NuGetCommand@2  displayName: 'Restore NuGet packages'  inputs:    restoreSolution: '$(solution)'# Сборка- task: VSBuild@1  displayName: Buld  inputs:    solution: '$(solution)'    platform: '$(buildPlatform)'    configuration: '$(buildConfiguration)'# Прогон юнит-тестов- task: VSTest@2  displayName: 'Run Unit Tests'  inputs:    platform: '$(buildPlatform)'    configuration: '$(buildConfiguration)'# Публикация собранной dll-ки в хранилище артефактов- task: CopyFiles@2  displayName: 'Copy plugins dll'  inputs:    SourceFolder: '$(Build.SourcesDirectory)\CRMCICD\Plugins\bin\Debug\'    Contents: 'CRMCI.*.dll'    targetFolder: '$(Build.StagingDirectory)/plugins'- publish: '$(Build.StagingDirectory)/plugins'  displayName: 'Publish plugins dll as an artifact'  artifact: plugins

Где $(xxx) это обращение к переменным которые я объявил сам или встроенным, подробнее смотреть тут Use predefined variables а описание что и в каких папках лежит можно посмотреть тут Understanding the directory structure created by Azure DevOps tasks.


И будьте внимательны, это YAML и один лишний или недостающий пробел может все поломать.

Сохраняем и запускаем пайп руками, кнопка Run pipeline справа вверху.



В следующем окне ничего не меняя просто жмем Run.



В результате чего попадаем на страницу конкретного экземпляра пайплайна который мы только что запустили и который стоит в очереди на исполнение где-то в недрах Azure DevOps. Он состоит из одной джобы (Job).



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



Если у кого-то не получилось можете взять версию пайпа из репозитория, коммит eb2a1465


Первое, что мне не нравится это версия пайпа, #20210129.1. Давайте сделаем свою, я обычно использую 4 цифры, где первые две это версия CRM а вторые 2 версия моих доработок, первая цифра это номер релиза а вторая номер сборки, например, 9.0.1.0. Данный подход позволяет иметь уникальный номер даже если одно и тоже решение делается для разных версий CRM. Получилось почти семантическое версионирование (подробнее см. https://semver.org/lang/ru/).


Итак, чтобы получить такой номер версии добавляем в пайп в секцию с переменными еще 3.


crmmajor: 9crmminor: 0rel: 1

И, между variables и steps добавляем следующую строчку


name: $(crmmajor).$(crmminor).$(rel).$(BuildID) 

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


Сохраняем и запускаем пайп. Теперь видим нашу версию в заголовке Jobs in run #9.0.1.7. Однако, наша новая версия не сохранилась ни в dll-ке с плагинами ни в решении.


Чтобы это исправить необходим PowerShell скрипт который лежит в папке CRMCI/Solution/BuildScripts/update-build-versions.ps1 это доработанный скрипт с сайта документации Microsoft по Azure DevOps Example: Version your assemblies, который меняет версию на текущую версию пайпа во всех dll и XML-файле решения CRM в проекте Solution.


Добавим его запуск перед сборкой проекта.


- task: PowerShell@2  displayName: 'Update version'  inputs:    filePath: '$(Build.SourcesDirectory)\CRMCI\Solution\BuildScripts\update-build-versions.ps1'    arguments: 'BUILD_BUILDNUMBER $(Build.BuildNumber) BUILD_SOURCESDIRECTORY $(Build.SourcesDirectory)'

Сохраняем и запускаем пайп. Проверяем, что в dll с плагинами, которая сохранилась в артефакты стоит правильная версия.
Теперь добавим сборку солюшена CRM, которая будет состоять из 2 задач, сама сборка и публикация солюшена в хранилище артефактов.


# Сборка решения CRM- task: CmdLine@2  displayName: 'Pack CRM Solution'  inputs:      script: |        dir        @echo off        set package_root=..\..\        REM Find the spkl in the package folder (irrespective of version)        For /R %package_root% %%G IN (spkl.exe) do (            IF EXIST "%%G" (set spkl_path=%%G            goto :continue)            )        :continue        REM spkl instrument [path] [connection-string] [/p:release]        "%spkl_path%" pack "$(Build.SourcesDirectory)\CRMCI\Solution\spkl.json" ""        exit /b %ERRORLEVEL%# Публикация решения CRM- task: CopyFiles@2  displayName: 'Copy CRM Solution'  inputs:      SourceFolder: '$(Build.SourcesDirectory)\CRMCI\Solution\'      Contents: 'CICDDemo_*.zip'      TargetFolder: '$(Build.StagingDirectory)/solutions'- publish: '$(Build.StagingDirectory)/solutions'  displayName: 'Publish solution as an artifact'  artifact: solutions

Сохраняем и запускаем пайп, проверяем, что помимо dll в артефактах еще появилось решение. Версия пайпа на текущий момент в коммите 647dae37.


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


- task: PowerShell@2  displayName: 'Copy CRMCI.Plugins.dll в папку решения'  inputs:    targetType: 'inline'    script: 'Copy-Item  -Path $(System.ArtifactsDirectory)\plugins\CRMCI.Plugins.dll  -Destination $(Build.SourcesDirectory)\CRMCI\Solution\package\PluginAssemblies\CRMCIPlugins-766F0C7B-4B44-EB11-A812-0022489AC434\CRMCIPlugins.dll -verbose'    errorActionPreference: 'silentlyContinue'

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


Если вы используете TypeScript или webpack или что-то подобное то необходимо добавить еще и сборку скриптов. В случае со spkl их тоже придется подкладывать в рабочую папку. :-(

В итоге мы получили пайп результат работы которого лежит в артефактах в виде dll с плагинами и солюшена CRM которые можно будет использовать для развертывания на среды в рамках CD для чего в AzureDevOps сделаны отдельные пайплайны Release pipelines. О них я расскажу в следующий раз.


Развертывание на локальную среду


Т.к. развертывание на локальную среду подразумевает доступ к локальной CRM то облачный агент нам не подойдет. Нужно настраивать свой. Как это сделать можно почитать тут Self-hosted Windows agents и тут How to create and configure Azure DevOps Pipelines Agent. Перед тем как устанавливать сам агент установите необходимое ПО, минимально это следующее:



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



Т.к. это отдельный этап и он должен выполняться на другом агенте то разобьем наш пайп на этапы, все что мы уже сделали это будет первый этап а деплой это второй. Для этого мы разобьем наш пайп на этапы (stages), которые в свою очередь состоят из джобов (jobs) которые в свою очередь уже состоят из уже знакомых нам тасков (tasks).


Здесь надо отметить, что для каждой джобы указывается агент (pool), что позволяет выполнять разные джобы на разных агентах специально заточенных под конкретную работу и экономить ресурсы дорогих агентов.

Если в этапе есть несколько джобов то они запустятся одновременно, это где-то полезно а где-то нет. Если нужно последовательное выполнение джобов то либо разнесите их по разным этапам либо проставьте условие dependsOn, подробнее тут Specify conditions.

Также, в пайпе можно перезапускать "упавшие" джобы а не конкретные такси. Учитывайте это при построении пайпа.

Структура следующая:


stages:- stage: Build  displayName: 'Build solution'  jobs:    - job: Build      displayName: 'Build job'      pool: 'Custom'      steps:      - task: NuGetToolInstaller@1        displayName: 'Install NuGet tool'- stage: Deploy  displayName: 'Deploy local'  jobs:    - job: Deploy      displayName: 'Deploy job'      pool: 'Custom'      steps:      - task: NuGetToolInstaller@1        displayName: 'Install NuGet tool'

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


Наш файл будет выглядеть так, коммит 97f91fec


trigger: nonepool:  vmImage: 'windows-latest'variables:  solution: '**/*.sln'  buildPlatform: 'Any CPU'  buildConfiguration: 'Debug'  crmmajor: 9  crmminor: 0  rel: 1name: $(crmmajor).$(crmminor).$(rel).$(BuildID)stages:- stage: Build  displayName: 'Build solution'  jobs:    - job: Build      displayName: 'Build job'      pool: 'Default'      steps:      # Установка NuGet      - task: NuGetToolInstaller@1        displayName: 'Install NuGet tool'      # Восстановление пакетов NuGet для проекта      - task: NuGetCommand@2        displayName: 'Restore NuGet packages'        inputs:          restoreSolution: '$(solution)'      # Обновление версии      - task: PowerShell@2        displayName: 'Update version'        inputs:          filePath: '$(Build.SourcesDirectory)\CRMCI\Solution\BuildScripts\update-build-versions.ps1'          arguments: 'BUILD_BUILDNUMBER $(Build.BuildNumber) BUILD_SOURCESDIRECTORY $(Build.SourcesDirectory)'      # Сборка      - task: VSBuild@1        displayName: Buld        inputs:          solution: '$(solution)'          platform: '$(buildPlatform)'          configuration: '$(buildConfiguration)'      # Прогон юнит-тестов      - task: VSTest@2        displayName: 'Run Unit Tests'        inputs:          platform: '$(buildPlatform)'          configuration: '$(buildConfiguration)'      # Публикация собранной dll-ки в хранилище артефактов      - task: CopyFiles@2        displayName: 'Publish plugins dll to artifacts'        inputs:          SourceFolder: '$(Build.SourcesDirectory)\CRMCI\Plugins\bin\Debug\'          Contents: 'CRMCI*.dll'          targetFolder: '$(Build.StagingDirectory)/plugins'      - publish: '$(Build.StagingDirectory)/plugins'        displayName: 'Publish plugins dll as an artifact'        artifact: plugins      # Сборка решения CRM      - task: CmdLine@2        displayName: 'Pack CRM Solution'        inputs:            script: |              dir              @echo off              set package_root=..\..\              REM Find the spkl in the package folder (irrespective of version)              For /R %package_root% %%G IN (spkl.exe) do (                  IF EXIST "%%G" (set spkl_path=%%G                  goto :continue)                  )              :continue              REM spkl instrument [path] [connection-string] [/p:release]              "%spkl_path%" pack "$(Build.SourcesDirectory)\CRMCI\Solution\spkl.json" ""              exit /b %ERRORLEVEL%      # Публикация решения CRM      - task: CopyFiles@2        displayName: 'Copy CRM Solution'        inputs:            SourceFolder: '$(Build.SourcesDirectory)\CRMCI\Solution\'            Contents: 'CICDDemo_*.zip'            TargetFolder: '$(Build.StagingDirectory)/solutions'      - publish: '$(Build.StagingDirectory)/solutions'        displayName: 'Publish solution as an artifact'        artifact: solutions- stage: Deploy  displayName: 'Deploy local'  jobs:    - job: Deploy      displayName: 'Deploy job'      pool: 'Default'      steps:      - task: NuGetToolInstaller@1        displayName: 'Install NuGet tool'

На странице пайплайна мы теперь видим два этапа.



Далее разберем таски второго этапа.
Первые две это восстановление NuGet пакетов чтобы у нас был доступен spkl.


Здесь, конечно, хорошо бы оптимизировать и закачивать только spkl т.к. остальное нам не нужно.

  # Установка NuGet  - task: NuGetToolInstaller@1    displayName: 'Install NuGet tool'  # Восстановление пакетов NuGet для проекта  - task: NuGetCommand@2    displayName: 'Restore NuGet packages'    inputs:      restoreSolution: '$(solution)'

Дальше начинаются костыли. :-) Т.к. я не нашел в spkl возможность импорта решения отдельно, там есть только совмещенный шаг сборки решения и его импорта import, который и придется использовать. Поэтому придется еще раз сделать обновление версии.


  # Обновление версии  - task: PowerShell@2    displayName: 'Update version'    inputs:      filePath: '$(Build.SourcesDirectory)\CRMCI\Solution\BuildScripts\update-build-versions.ps1'      arguments: 'BUILD_BUILDNUMBER $(Build.BuildNumber) BUILD_SOURCESDIRECTORY $(Build.SourcesDirectory)'

Теперь собираем и импортируем решение. Для этого нам понадобится строка подключения к CRM, которую мы сохраним в переменные пайпа под именем connstr-local. Кнопку добавления переменных можно найти на странице редактирования пайпа.



  # Импорт решения CRM  - task: CmdLine@2    displayName: 'Deploy solution'    inputs:      script: |        @echo off        set package_root=..\..\        For /R %package_root% %%G IN (spkl.exe) do (          IF EXIST "%%G" (set spkl_path=%%G          goto :continue)          )        :continue        @echo Using '%spkl_path%'         "%spkl_path%" import "$(Build.SourcesDirectory)\CRMCI\Solution\spkl.json" "$(connstr-local)"        if errorlevel 1 (        echo Error Code=%errorlevel%        exit /b %errorlevel%        )

По хорошему, надо скачивать решение собранное на предыдущем этапе и импортировать его, это можно сделать с помощью PowerShell или написать консольку.

Дальше мы скачиваем собранную dll-ку с плагинами и подкладываем туда где она должна оказаться если бы мы собирали решение т.к. я не нашел способа явно параметром указать откуда брать dll при импорте плагинов. Опять костыль. :-)


  # Скачивание плагинов  - task: DownloadPipelineArtifact@2    displayName: 'Download plugins artifacts'    inputs:      buildType: 'specific'      project: 'b44552ad-1d85-4c3b-834b-5109b4c9c2b4'      definition: '1'      buildVersionToDownload: 'latest'      artifactName: 'plugins'      targetPath: '$(System.ArtifactsDirectory)/plugins'  # Копируем dll  - task: CopyFiles@2    displayName: 'Copy plugins dll'    inputs:      SourceFolder: '$(System.ArtifactsDirectory)\plugins'      Contents: '*.dll'      TargetFolder: '$(Build.SourcesDirectory)\CRMCI\Plugins\bin\Debug\'      OverWrite: true

Следующий шаг это импорт плагинов, в том числе и шагов.


  # Импорт плагинов  - task: CmdLine@2    displayName: 'Deploy plugins'    inputs:      script: |        @echo off        set package_root=..\..\        For /R %package_root% %%G IN (spkl.exe) do (          IF EXIST "%%G" (set spkl_path=%%G          goto :continue)          )        :continue        @echo Using '%spkl_path%'         "%spkl_path%" plugins "$(Build.SourcesDirectory)\CRMCI\Plugins\spkl.json" "$(connstr-local)"        if errorlevel 1 (        echo Error Code=%errorlevel%        exit /b %errorlevel%        )

Ну и последним шагом будет импорт веб-ресурсов. Тут spkl просто берет файлы из проекта и публикует их согласно маппингу в spkl.json.


  # Импорт веб-ресурсов  - task: CmdLine@2    displayName: 'Deploy web-resources'    inputs:      script: |        @echo off        set package_root=..\..\        For /R %package_root% %%G IN (spkl.exe) do (          IF EXIST "%%G" (set spkl_path=%%G          goto :continue)          )        :continue        @echo Using '%spkl_path%'         "%spkl_path%" webresources "$(Build.SourcesDirectory)\CRMCI\\WebResources\spkl.json" "$(connstr-local)"        if errorlevel 1 (        echo Error Code=%errorlevel%        exit /b %errorlevel%        )

Вот, собственно, и все. Теперь можно вернуть триггер на срабатывание по коммиту в ветке main.


trigger:- main

Но это не совсем то, что нам нужно т.к. пайп будет вызываться на изменение любого файла, в том числе, самого файла azure-pipelines.yml что не всегда удобно. Поэтому, в секцию trigger можно добавить исключения по ветке, тегу или по маске. Я добавил следующее.


trigger:  branches:    include:    - main  paths:    include:    - '*'    exclude:    - 'azure-pipelines.yml'    - '*.md'

Также если в комментарии к коммиту присутствует одно из следующих словосочетаний то он не запустится:


  • [skip ci] or [ci skip]
  • skip-checks: true or skip-checks:true
  • [skip azurepipelines] or [azurepipelines skip]
  • [skip azpipelines] or [azpipelines skip]
  • [skip azp] or [azp skip]

Подробнее смотрите здесь CI triggers


Первая часть закончена, CI построен и даже немного больше. Тут, есть конечно, куда развиваться, например, добавить статический анализ кода (кому интересно см. лабу Подключение SonarCloud к AzureDevops) или автотесты.


В следующей статье расскажу про релизные пайплайны и CD.

a2-ia.png)
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru