Введение
В условиях постоянного роста требований к качеству и скорости разработки к команде разработчиков вопросы оптимизации и совершенствования процесса работы в области программирования приобретают прикладное значение. Сегодня процессы, связанные с разработкой программного обеспечения (далее – ПО), становятся все более сложными и динамичными. В подобных условиях возникает потребность в разработке эффективных и автоматизированных методик для обеспечения надежной доставки программного продукта в промышленную среду. С одной стороны, имеются требования заказчика, которые с каждым днем изменяются ввиду различных причин (выявление проблем продукта в ходе использования, уточнение необходимости внедрения дополнительного функционала, растущие запросы на цифровизацию и многие другие причины). С другой стороны, существует команда разработчиков, ответственная за разработку ПО, его качество, уровень оптимизации, а также сроки его поставки в компанию (дата релиза). Первопричиной необходимости повышения скорости и слаженности работы команды в процессе разработки ПО становится именно ускорение даты релиза, что требует реализации процедур автоматизации, позволяющих при отсутствии высоких затрат увеличить скорость выполнения задач разработчиками. Существуют различные пути оптимизации скорости работы команды разработчиков ПО, например, найм дополнительных сотрудников, однако подобные способы сказываются на издержках, закономерно увеличивая стоимость программных решений и оказывая не последнее влияние на его доступность, востребованность и конкурентоспособность в условиях рынка. Более того, не всегда подобные способы позволяют преодолеть проблему согласования действий сотрудников, ускорения выполнения работы. Таким образом, возникает проблема, связанная с поиском наиболее оптимальных путей повышения эффективности работы команды разработчиков.
Continuous Integration/Continuous Deployment (далее – CI/CD) является одним из самых распространенных и эффективных подходов к автоматизации и оптимизации процессов разработки и доставки программного обеспечения. Реализация данной DevOps практики не требует высоких затрат и при эффективной реализации позволяет улучшить качество разработки и повлиять в конечном счете на скорость доставки программного обеспечения. Достижение заданных преимуществ основано на применении специальных подходов. В данной статье предполагается проведение разработки методики построения CI/CD, которая позволит повысить эффективность и качество процессов разработки и доставки программного обеспечения.
Цель статьи – разработать методику построения непрерывной интеграции и непрерывного развертывания (СI/CD) для задач подготовки программного обеспечения (ускорения разработки и доставки ПО).
Литературный обзор
Исследованию CI/CD сегодня посвящается все больше научных работ, раскрывающих отдельные вопросы, практики и подходы к построению CI/CD с перспективой улучшения процессов разработки. Так, по мнению А.А. Невского CI/CD служит инструментом улучшения промышленных практик, что требует разработки эффективной комбинации [4]. Комбинация CI/CD представляет под собой раскрытие системы шагов при выполнении процедур CI/CD в ходе работы DevOps-инженера. Построение CI/CD является прикладной задачей в процессе разработки программного обеспечения, ключевое назначение которой – автоматизировать процесс разработки, что в особенности значимо в сложных проектах.
М.В. Безпятый верно отмечает, что сегодня в практике DevOps высокое значение приобретает организация работы по автоматизации и оптимизации, что связано с комплексной трансформацией процессов разработки и последующего развертывания ПО. Автор выделяет множество подходов к автоматизации в деятельности DevOps-инженера, указывая на высокую перспективу CI/CD [2]. Опираясь на исследование М.В. Безпятого, отметим, что сегодня деятельность разработчика может быть значительным образом улучшена – это связано с поиском новых практик оптимизации и автоматизации работы, с перспективой влияния не только на скорость работы, но и на качество подготавливаемых программных продуктов. Прикладное значение CI/CD достаточно наглядно продемонстрировано в работе М.В. Денисовой, которая показывает, как CI/CD влияет на процессы организации дистанционного обучения. По итогам исследования автор показывает, что CI/CD способствует не только эффективному тестированию разработок преподавателя, но и позволяет проверять базовый рабочий процесс, улучшить контроль за средой и т.д. [7].
Е.А. Басыня указывает на необходимость улучшения программного обеспечения путем использования автоматических тестов и инструментов непрерывной интеграции [1]. Отметим, что CI/CD действительно является способом быстрого рецензирования кода, проверки программного обеспечения, позволяющим воспроизводить гибкий подход (Agile) к управлению разработкой. Аналогичные выводы прослеживаются в работе А.Г. Феоктистова и соавторов, которые считают, что CI/CD позволяет учитывать специфику решаемых задач, расширить спектр подходов к разработке программного обеспечения, использовать конкретные предметные данные, сокращать общее число ошибок и сбоев на прикладном уровне, увеличить эффективность задействованных ресурсов [5]. И.В. Кузьмина и В.Р. Фидельман указывают на эволюционирование подходов к непрерывной интеграции приложений, что требует постоянного улучшения практических способов организации CI/CD [3]. В исследовании А.Н. Черных и соавторов CI/CD рассматривается как способ сокращения факторов неопределенности в разработке, обеспечивающий надежность вычислительных операций и повышение эффективности использования ресурсов. По итогам исследования авторы приходят к выводам о том, что инструментарий CI/CD демонстрирует ряд относительных преимуществ в работе разработчиков при решении прикладных задач [6].
Тематика CI/CD пользуется спросом также и в трудах зарубежных исследователей, которые не только описывают возможности, преимущества и ситуации эффективного применения CI/CD в деятельности DevOps-инженера, но и раскрывают собственные подходы к организации CI/CD. Так, в исследовании B. Smith и соавторов особое внимание уделяется именно проблеме оптимизации затрат на разработку и доставку программного обеспечения, с перспективами удовлетворения всех ожиданий будущих пользователей. Авторы указывают на высокое прикладное значение решения задач модернизации подходов к разработке программного обеспечения, формирования лучших практик и использования декларативных способов организации автоматизации [12]. Иными словами, авторы указывают на высокую ценность разработки конкретизированных подходов к организации оптимизационных процедур. В качестве достаточно эффективных оптимизационных процедур можно выделить CI/CD, которые на практике отвечают задачам улучшения разработки. S.P. Sinde и соавторы фокусируются на раскрытии специфических механизмов реализации процедур CI/CD, указывая на факт того, что CI/CD обеспечивает автоматизацию и непрерывный мониторинг работы разработчиков программного обеспечения на протяжении всего проекта. CI/CD используется для непрерывной интеграции и доставки и требует в ряде случаев применения оптимизационных настроек, дабы обеспечить высокое качество исполнения рабочих процессов [11]. S. R. Dileepkumar и D. Mathew считают, что именно поставка программного обеспечения вызывает наибольшее число проблем, связанных с необходимостью постоянного совершенствования программы за счет исправления возникающих ошибок в приложении. CI/CD по мнению авторов служит практическим инструментом обеспечения гибкости поставок программного обеспечения с заведомо известным качеством и соблюдением установленных сроков. CI/CD соответствует задачам перехода в облачный формат развертывания вычислений, демонстрируя высокий уровень экономической эффективности и относительную простоту реализации [8]. Эти и многие другие преимущества CI/CD зависят от конкретного подхода к развертыванию процессов реализации, что указывает на существенные перспективы разработки методики построения CI/CD.
Согласимся и с позицией F. Sethi, отожествляющей CI/CD двум векторам, в которых оба имеют единое направление и разную величину [10]. CI/CD призвана ускорить процесс разработки ПО и улучшить качество кода за счет использования ряда надежных способов, например, автоматической подготовки и отслеживания выпуска для производства, реализации типовых (рутинных) операций, что сказывается на продуктивности команды разработчиков и позволяет следовать намеченным стандартам. Перспектива CI/CD существенна и с точки зрения её внедрения в управление разработкой, с централизованным развертыванием и использованием в качестве основы формирования инфраструктуры. P.N. Mahendra и соавторы считают, что CI/CD при применении в структуре управления командой разработчиков позволяет направить существующий поток процессов на реализацию единой цели, параллелизировать работу нескольких разработчиков без создания препятствий и противоречий в их взаимодействии. Авторы называют CI/CD лучшей практикой быстрого и безостановочного совершенствования программного обеспечения. Тем не менее, в исследовании также выделяется наличие противоречий в области поиска наиболее эффективных методик построения CI/CD, что по мнению авторов является значимым направлением будущих исследований [9]. M. Shanin и соавторы провели детальное исследование существующих практик построения CI/CD, указывая на тридцать подходов и внутренних инструментов CI/CD, позволяющих достигать поставленных целей при заданных условиях совершенствования процессов разработки программного обеспечения. По итогам исследования авторы приходят к выводам о том, что для более точного и эффективного воспроизводства CI/CD требуется учитывать такие параметры, как время тестирования, область применения, существующая инфраструктура, которые значительно сказываются на итоговой организации CI/CD [13].
Таким образом, результаты проведенного литературного обзора позволяют заключить, что в современном научно-исследовательском поле тема CI/CD становится все более востребованной. Несмотря на множественные попытки описания, классификации или улучшения CI/CD, зачастую, CI/CD основана на специфических задачах и проектах, требует учета входных данных, что сказывается на результатах применения отдельных методик. При отклонении от условий, в которых конкретная методика продемонстрировала эффективность, результативность построения CI/CD может значительно сократиться. Сохраняется весомое значение решения задач поиска оптимального и универсального способа (методики) построения CI/CD, что определяет перспективу раскрытия подходов из реальной практики автора настоящего исследования.
Система контроля версий
Первым шагом в построении CI/CD является настройка системы контроля версий (например, Git). Использование «версионного» хранения стало неотъемлемой частью современной разработки программного обеспечения и проектов совместной работы. Версионное хранение или системы контроля версий – это механизм для отслеживания и управления изменениями в файлах и документах, используемых в различных проектах разработки и других типах проектов. Каждое изменение в коде должно быть зафиксировано.
Система контроля версий предоставляет следующие преимущества команде разработчиков:
- история изменений помогает отслеживать, кто, когда и по какой причине вносил изменения в проект. Это особенно значимо при отладке, поиске причин ошибок и восстановлении предыдущих версий;
- коллаборация. Каждый член команды может работать над своей копией файлов и объединять изменения в общий репозиторий, что позволяет эффективно сотрудничать над проектом;
- откат изменений позволяет отменить нежелательные изменения и восстановить предыдущие версии файлов или документов. Это обеспечивает безопасность при внесении изменений и устранении ошибок;
- резервное копирование. Каждое изменение в системе контроля версий сохраняется, что обеспечивает автоматическое резервное копирование данных;
- ветвление помогает экспериментировать с новыми функциями или изменениями, не затрагивая основной код проекта до завершения и тестирования;
- версионное маркирование позволяет помечать и выпускать стабильные версии программного продукта, что облегчает обновление и отслеживание выпусков.
Использование системы контроля версий позволяет разработчикам эффективно управлять изменениями и обеспечивает стабильность, безопасность и надежность проектов.
Коммиты
Коммит (commit) представляет собой запись или точку сохранения изменений в кодовой базе проекта. Каждый коммит содержит информацию о том, какие конкретные изменения были внесены, кто сделал эти изменения и в какой момент времени. Коммиты используются для отслеживания истории изменений, обеспечивая возможность вернуться к определенному состоянию проекта в будущем и управлять совместной разработкой.
Коммиты следует делать, когда вносятся существенные изменения в кодовую базу, которые предполагается сохранить и использовать в дальнейшем. Например, это может быть добавление новой функциональности, исправление ошибки, оптимизация кода или какие-либо другие изменения, которые влияют на работу программы. Каждый коммит должен быть логически связан с определенной задачей или изменением, чтобы облегчить понимание истории изменений в будущем.
Частота создания коммитов зависит от конкретного проекта, но существует несколько рекомендаций:
- частые и маленькие коммиты. Достаточно эффективной практикой является частое создание небольших коммитов. Это позволяет отслеживать изменения пошагово и облегчает просмотр и рецензирование кода. Каждый коммит может быть ограничен определенными изменениями, таким образом, весь процесс разработки более структурирован и предсказуем;
- логическая разбивка. Разделение изменений на логические блоки, что позволяет в дальнейшем учитывать этапность разработки. Например, если осуществляется работа над новой функциональностью, необходимо разделите её на несколько этапов и создавать коммиты после завершения каждого этапа;
- создание коммитов перед выполнением важных действий, таких как изменение архитектуры или внесение существенных изменений в код. Это помогает создать точку восстановления, которая используется в случае неполадок;
- коммиты перед отправкой на рецензию. В процессе работы в команде рекомендуется создавать коммиты перед отправкой кода на рецензию. Это позволит другим разработчикам оценить код и предоставить обратную связь;
- необходимо придерживаться логической структуры и удобочитаемости при создании коммитов, чтобы облегчить разработчикам работу с кодом.
Можно выделить некоторый стандарт написания коммитов:
1. Краткое и информативное сообщение. Каждый коммит должен иметь краткое и информативное сообщение, которое описывает изменение. Как правило, описание включает в себя 50-72 символа для первой строки, чтобы она была читаемой в различных инструментах.
2. Использование тегов (опционально). Теги используются в сообщении коммита, чтобы явно указать тип изменения:
- feat – внесены изменения для добавления новой функции;
- fix – произведено исправление ошибки;
- chore – изменения, которые не связаны с исправлением или новой функцией, и не модифицируют исходные или тестовые файлы (например, обновление зависимостей);
- refactor – рефакторинг кода, который не исправляет ошибку и не добавляет новую функцию (например переименование переменной);
- docs – обновления документации, такие как README или другие файлы в формате markdown;
- style – изменения, связанные с форматированием кода, таким как пробелы, отсутствие точек с запятой и так далее.;
- test – добавление новых тестов или корректировка предыдущих тестов;
- perf – улучшения производительности;
- ci – связанные с непрерывной интеграцией;
- build – изменения, влияющие на систему сборки или внешние зависимости;
- revert – отмена предыдущего коммита.
3. Использование повелительного наклонения. Предполагает написание сообщений в повелительном наклонении, начиная с глагола. Например: «Добавьте функцию X», «Исправьте баг Y», «Обновите зависимости».
4. Спецификация контекста. В случае необходимости основное сообщение дополняется описанием контекста или причиной изменения. Это может быть вторая строка коммита, разделенная пустой строкой.
5. Ориентация на аккуратность. Необходимо избегать лишних пробелов, опечаток и ненужных символов в коммите.
Достаточно наглядным примером, верно составленного коммита является следующий (рис. 1):
Рис. 1. Пример верно составленного коммита
Запросы на слияние
Запросы на слияние (или pull request, также известные как merge request) – это важная практика в системах контроля версий, используемая при совместной разработке программного обеспечения. Они представляют собой механизм для интеграции изменений из одной ветки (обычно ветки фич или исправлений) в другую (например, основную ветку или ветку разработки). Запросы на слияние необходимы для следующих задач:
- рецензирование кода. Запрос на слияние позволяет команде разработчиков рецензировать предполагаемые изменения. Коллеги могут просмотреть код, комментировать его, предлагать улучшения и проверять, что все соответствует стандартам кодирования и требованиям проекта;
- обсуждение и коммуникация. В рамках запроса на слияние возможно обсудить изменения, задать вопросы и предложить идеи. Это помогает согласовать изменения, улучшить качество кода и обеспечить обмен знаний между участниками проекта;
- избегание конфликтов. В случае, когда несколько разработчиков работают над одной и той же частью кода одновременно, запрос на слияние помогает избежать конфликтов в коде, которые могут возникнуть при попытке объединения изменений напрямую;
- тестирование. Перед тем как изменения попадут в основную ветку, их можно протестировать на соответствие функциональности и отсутствие ошибок. Это помогает избежать внесения проблемных изменений в основную кодовую базу;
- отслеживание истории изменений. Запросы на слияние создают понятную историю изменений. Каждый запрос может быть прокомментирован, а его история будет видна в системе контроля версий. Это помогает отслеживать, кто, в какой момент времени и по какой причине вносил изменения;
- безопасность и контроль качества. Запросы на слияние позволяют команде поддерживать высокий уровень качества кода и контролировать процесс интеграции изменений в основную кодовую базу.
Так, запросы на слияние обеспечивают более структурированный и обоснованный процесс интеграции изменений, что помогает улучшить совместную разработку и поддержание проектов.
Ревью кода
Ревью кода (или код-ревью) – это практика в разработке программного обеспечения, при которой другие разработчики из команды или сообщества анализируют и обсуждают код, написанный одним из участников проекта, с целью повысить качество, надежность и понимание кодовой базы. Это важный этап в процессе разработки, который помогает выявить ошибки, улучшить архитектуру, обменяться знаниями и поддержать единые стандарты кодирования.
Ревью кода может проводиться различными способами, например, с помощью систем для контроля версий, где разработчики могут оставлять комментарии и предложения по улучшению кода. Основные цели ревью кода включают в себя:
- Обнаружение ошибок. Другие разработчики могут выявить ошибки, которые автор кода мог не заметить, такие как потенциальные утечки памяти, неправильное использование функций или пропущенные проверки на входных данных.
- Улучшение качества кода. Разработчики могут предложить улучшения в структуре кода, оптимизации, использовании паттернов проектирования и других аспектах, чтобы сделать код более читаемым, эффективным и поддерживаемым.
- Поддержание стандартов. Ревью кода способствует соблюдению единых стандартов кодирования и архитектурных решений в проекте, что улучшает согласованность кодовой базы.
- Обмен знаниями. Ревью кода предоставляет возможность разработчикам обмениваться знаниями и опытом, учиться друг у друга и развиваться профессионально.
- Повышение надежности. Путем анализа и обсуждения кода можно выявить уязвимости, недочеты в безопасности и другие проблемы, которые могут повлиять на надежность программы.
- Снижение технического долга. Ревью кода помогает выявить участки кода, требующие рефакторинга или улучшений, что способствует снижению накопленного технического долга.
Таким образом, ревью кода способствует созданию более качественного и надежного программного обеспечения, а также повышает уровень сотрудничества и коммуникации в команде разработки. Проведение ревью кода – это структурированный и целенаправленный процесс, который требует внимания, терпимости и сотрудничества. Для того чтобы с большей эффективностью проводить ревью кода, необходимо следовать ряду принципов:
- Ревью кода следует проводить на этапе, когда разработчик закончил написание кода и готов передать его на обзор. Нежелательно начинать ревью слишком рано или слишком поздно.
- Необходимо установить четкие критерии и ожидания для ревью, определить, какие аспекты кода должны быть оценены: структура, читаемость, производительность, безопасность и т. д.
- Применение множества инструментов и платформ (например, GitHub, GitLab, Bitbucket), которые предоставляют функциональность для ревью кода, что делает процесс более структурированным.
- Рецензенты могут оставлять комментарии непосредственно в коде или в системе ревью. При этом комментарии должны быть конструктивными и доходчивыми.
- Разработчику, сдавшему код на ревью, необходимо быть готовым объяснить свои решения и обосновать принятые дизайн-решения. Это способствует пониманию и снижает вероятность недопониманий.
- Ревью кода целесообразно направить на улучшение кода и процесса разработки. Комментарии к коду следует формулировать так, чтобы обратить внимание на конкретные проблемы.
- Разработчику целесообразно выбирать наиболее критичные и значимые с точки зрения улучшения кода комментарии.
- Ревью кода является возможностью для организации обучения и обмена опытом между членами команды. Разработчики могут учиться друг у друга, делясь знаниями о лучших практиках и технических аспектах.
- После завершения ревью необходимо убедиться, что все обсуждения, комментарии и решения были достаточно задокументированы. Это позволит отслеживать изменения и обсуждения в будущем.
- Необходимо проводить постоянный анализ, направленный на установление того, каким образом можно улучшить процесс ревью, чтобы сделать его более эффективным и продуктивным.
Важно понимать, что ревью кода – это совместный труд команды, направленный на достижение общей цели – создание качественного программного обеспечения.
Организация работы с Git
Существует несколько подходов для организации работы с версионным контролем и управлению разработкой ПО. Среди основных подходов из личной практики автора можно выделить:
1. Git-flow
Git-flow – это модель ветвления, предложенная Vincent Driessen, которая определяет строгий набор ветвей и правил для их использования.
- main (или master) – содержит текущую выпущенную версию кода и должен соответствовать коду, который находится в продакшене;
- develop – содержит копию основной ветки с добавленными изменениями, которые были внесены с момента последнего релиза;
- feature – разработчики создают ветви feature на основе ветки develop для работы над новыми функциями. В отличие от веток main и develop, нет единственной ветки с названием feature. Имена веток обычно выбираются в зависимости от внесенных изменений, например bug/StackOverflowFixInService. Если вы используете JIRA и настроили интеграцию с GitHub или Bitbucket, вы также можете видеть номер задачи JIRA в имени ветки, чтобы она отображалась в задаче JIRA, например task/PRJ-1234-AddCardPage;
- release – после завершения работы разработчиков над изменениями создается новая ветка, которая объединяется из ветки develop для создания релиза. Ветка обычно названа по номеру релиза, например release/1.2.3;
- hotfix – если существует срочная проблема в продакшене, требующая исправления кода, создается ветка hotfix. Она создается непосредственно из ветки main и обычно названа по инциденту, например hotfix/INC1234-InvalidPageMatch.
Рис. 2. Построение Git-flow
Git-flow эффективен в проектах с долгим циклом разработки, где есть несколько версий продукта, которые поддерживаются параллельно. Git-flow используется, когда требуется высокий уровень стабильности и контроля над релизами, и когда команда разработки обладает опытом и желанием следовать строгому процессу.
2. GitHub Flow.
GitHub Flow – это более простая и линейная модель ветвления, предложенная GitHub, которая подходит для более быстрых и частых релизов.
С использованием подхода GitHub flow у разработчика всегда есть только 2 ветки:
- main (или master) – аналогично GitFlow, основная ветка содержит весь код, который можно развернуть для проекта;
- feature – разработчики создают ветки непосредственно от main для работы над новыми функциями.
Рис. 3. Построение GitHub Flow
GitHub Flow рекомендуется для небольших команд и проектов с активной разработкой и доставкой ПО. GitHub Flow основан на создании небольших feature-веток, которые после завершения протестированы и затем вливаются в основную ветку (обычно это master или main).
3. Trunk-Based Development
Trunk-Based Development (далее – TBD) – это методология, которая предполагает непрерывное вливание (merge) кода в основную ветку (trunk или main) проекта.
Рис. 4. Построение Trunk-Based Development
Этот подход применяется, когда команда стремится к высокой скорости разработки, уменьшению времени нахождения ошибок и более быстрой доставке функциональности пользователям. Trunk-Based Development эффективен в командах с хорошо налаженными тестами и автоматизированными процессами развертывания.
4. Scaled Trunk-Based Development
Scaled Trunk-Based Development (далее – STBD) – это расширение методологии TBD для больших и сложных проектов или организаций. В этом случае, когда проект масштабируется, возникают проблемы с конфликтами и сложностью интеграции кода. STBD включает стратегии и практики для управления масштабированным процессом разработки на основе основной ветки.
Рис. 5. Построение Scaled Trunk-Based Development
Построение Scaled Trunk-Based Development может включать в себя подходы к разделению кодовой базы на модули, частичную автоматизацию слияний, введение Code Review и другие подходы.
Отметим, что выбор конкретного подхода зависит от различных факторов, таких как размер команды, сложность проекта, уровень опыта команды, требования к частоте и стабильности релизов и другие факторы. Некоторые команды могут адаптировать или комбинировать различные подходы для нахождения наилучшего сочетания для своего проекта. Важно помнить, что не существует универсального правила, и каждая команда должна выбрать подход, который наилучшим образом соответствует её потребностям и проекту.
Окружения
Определение окружений для Agile команд разработки – это процесс создания различных сред для тестирования и развертывания программного обеспечения на разных этапах его разработки. Эти окружения предоставляют изолированные и контролируемые условия для проверки функциональности, интеграции, производительности и других аспектов ПО перед его выпуском в промышленную среду.
В Agile разработке, в частности, в методологии CI/CD, определение окружений является важной частью процесса. Среди типичных окружений, которые Agile команды могут определить, можно выделить следующие:
- песочница (Sandbox Environment). Это среда для написания тестов и проведения экспериментов, позволяя разработчикам работать, не влияя на другие среды или реальных пользователей. Это окружение используется для отладки кода и выявления ошибок до того, как код будет смержен в develop или main ветку;
- DEV окружение (Development Environment). Это более структурированное и стабильное окружение, в котором разрабатывается и интегрируется код от разных разработчиков. Это окружение обычно представляет собой рабочую ветку (например, «develop» в GitFlow), где разработчики объединяют свои изменения и проводят тестирование и интеграцию. Оно также может быть использовано для проведения Code Review и проверки стабильности перед тем, как код попадет в более стабильные окружения, такие как staging или production. Т.е. develop окружение должно быть построено на основе «зеленой сборки» или «зеленого конвейера». Это означает, что код, который интегрируется и развертывается в develop окружении, должен всегда проходить успешные тесты и другие проверки, чтобы убедиться в его стабильности и работоспособности;
- тестовое окружение (Testing Environment). Это окружение предназначено для тестирования ПО на более реалистичных данных и условиях, схожих с промышленной средой. Здесь проводятся функциональные, интеграционные, нагрузочные и другие виды тестирования;
- стейджинг окружение (Staging Environment). Это окружение представляет собой полную копию промышленной среды. Здесь проходит окончательное тестирование перед выпуском в промышленную среду. Также оно используется для демонстрации новых функций заказчикам или заинтересованным сторонам;
- промышленная среда или продакшн окружение (Production Environment). Это окружение, в котором работает фактический продукт, доступный пользователям. Код и данные, находящиеся в промышленном окружении, требуют стабильности и надежности.
Каждое окружение необходимо изолировать друг от друга, обеспечивать постепенное и контролируемое движение программного обеспечения от этапа разработки до выпуска. В Agile методологии, команды стремятся автоматизировать процессы развертывания и тестирования, чтобы ускорить цикл разработки и обеспечить непрерывную готовность к поставке качественного ПО.
Continuous Integration – непрерывная интеграция
Основная задача Continuous Integration (CI) заключается в автоматизации и регулярной интеграции кода разработчиков в общую кодовую базу. Это практика, которая способствует более эффективному и безопасному процессу разработки программного обеспечения. Основной целью CI является поддержание стабильности и высокого качества кода, а также обеспечение непрерывной готовности продукта к развертыванию в промышленной среде за счет реализации системы процессов (рис. 6).
Рис. 6. Ключевые процессы при Continuous Integration
Обращаясь к рис. 6, выделим некоторые ключевые задачи Continuous Integration:
- При каждом коммите кода в репозиторий автоматически запускается процесс сборки, который компилирует исходный код в исполняемый продукт. Это позволяет быстро обнаруживать ошибки, связанные с некорректной сборкой.
- Continuous Integration включает в себя выполнение различных видов автоматизированных тестов, таких как unit-тесты, интеграционные тесты, функциональные тесты и другие. Цель этих тестов – обнаружить ошибки в коде на ранних этапах разработки, чтобы избежать их накопления и улучшить стабильность продукта.
- Проверка Quality Gate – это концепция, которая используется для оценки качества кода перед его автоматическим развертыванием в промышленную среду. Это набор критериев и условий, в соответствие с которыми необходимо формировать код, чтобы обеспечить его готовность для развертывания.
- Автоматически интегрирует изменения разных разработчиков в общую кодовую базу. Это позволяет быстро выявлять и разрешать конфликты, которые могут возникнуть из-за одновременных изменений в одном и том же участке кода.
- Периодически объединяет код разработчиков вместе с основной кодовой базой. Это создает регулярные точки интеграции, на которых происходит проверка корректности и стабильности системы.
- Обеспечивает быструю обратную связь разработчикам о статусе и качестве их изменений. Если тесты не проходят успешно, разработчики получают информацию о возникших проблемах и могут оперативно реагировать на них.
- Помогает гарантировать, что код всегда находится в состоянии, пригодном для развертывания в промышленной среде. Это упрощает процесс непрерывной доставки и уменьшает риски, связанные с релизами.
- Благодаря регулярной проверке кода и автоматическому обнаружению ошибок, CI помогает предотвращать накопление технического долга – неразрешенных проблем в коде, которые могут замедлить разработку в будущем.
- Если сборка успешна, генерируется артефакт (например, исполняемый файл, контейнер, архив и т.д.), который представляет собой готовое приложение. Артефакт загружается в хранилище артефактов, такое как JFrog Artifactory, Nexus или Docker Hub. Это хранилище обеспечивает управление версиями артефактов и их доступность для различных сред и этапов.
Если команда собирает релизную версию продукта, то сборка выполняется, как правило, один раз для всех окружений. Это правильно поможет предотвратить проблемы, возникающие при многократной компиляции или упаковке программного обеспечения, в результате чего могут возникать небольшие несоответствия или ошибки. Отдельная сборка программного обеспечения на каждом новом этапе означает, что в предыдущем тестировании использовалось не то же самое программное обеспечение, что делает результаты недействительными. Полученную сборку с присвоенным номером версии выгружают в хранилище артефактов, откуда она будет извлекаться на следующих частях конвейера. Это гарантирует, что на разных участках системы будет использоваться одна и та же сборка.
Так, CI способствует улучшению сотрудничества в команде разработчиков, повышению качества ПО и ускорению процесса доставки продукта пользователям.
Continuous Deployment – непрерывное развертывание
Основная задача Continuous Deployment (CD) – это автоматизированная и непрерывная поставка готового программного обеспечения в промышленную среду после успешного прохождения всех этапов Continuous Integration (CI) и проверок качества за счет реализации системы процессов (рис. 7).
Рис. 7. Ключевые процессы при Continuous Deployment
Обращаясь к рис. 7, выделим некоторые ключевые задачи Continuous Deployment:
- После успешного прохождения всех тестов и проверок на этапе CI, CD автоматически выполняет процесс развертывания программного обеспечения в промышленную среду без вмешательства разработчиков.
- Continuous Deployment помогает поддерживать код в постоянно готовом состоянии для развертывания, что ускоряет релизы и позволяет оперативно реагировать на изменения требований и рыночных условий.
- Позволяет создавать и настраивать необходимые окружения (тестовые, пре-промышленные, промышленные) автоматически, что упрощает тестирование и внедрение изменений в различные среды.
- Автоматическое развертывание снижает риски человеческих ошибок при ручном развертывании ПО, так как весь процесс строго контролируется и автоматизируется.
- Позволяет управлять конфигурациями и зависимостями приложения в различных средах, обеспечивая согласованность окружений.
- Благодаря автоматическому развертыванию, любые проблемы или ошибки в процессе развертывания обнаруживаются немедленно, что позволяет быстро реагировать и вносить исправления.
- Способствует частым релизам, что позволяет быстрее внедрять новые функции и улучшения, поддерживать конкурентоспособность продукта и удовлетворять потребности пользователей.
- Обеспечивает мониторинг работы продукта после развертывания, и в случае возникновения проблем позволяет автоматически вернуть изменения к предыдущей стабильной версии.
Так, основной целью CD является обеспечение быстрой и надежной доставки ПО пользователям с минимальными рисками и усилиями.
Написание конвейера или pipeline
Создание универсальных конвейеров для Continuous Integration/Continuous Deployment (CI/CD) – это важная практика, которая позволяет упростить управление, поддержку и масштабирование процессов разработки и развертывания. Практический опыт автора позволяет выделить некоторые принципы и практики, которые позволяют создавать универсальные конвейеры:
- Определение конвейеров в виде кода (Infrastructure as Code), что облегчает версионирование, совместную работу и повторное использование.
- Параметризация конвейеров, чтобы они могли быть настроены для различных проектов, веток, окружений и других параметров. Это позволит использовать один и тот же конвейер с разными конфигурациями.
- Разделение конвейера на логические этапы, такие как сборка, тестирование, развертывание и т. д. Каждый этап должен выполнять конкретные задачи и иметь четкую цель.
- Выделение общих шагов и функций в отдельные модули (например reusable workflow в Github Actions) или библиотеки (например shared library в Jenkins), которые можно использовать повторно в разных конвейерах. Такой подход называется DRY (Don't Repeat Yourself), он сформулирован как один из принципов Agile-разработки и его принято считать ключевым аспектом эффективного проектирования ПО. Это помогает избежать дублирования кода и упрощает обновление и поддержку.
- При наличии зависимостей в конвейере, таких как Docker образы или внешние библиотеки, целесообразно использовать систему управления зависимостями для их управления и версионирования.
- Создание тестов для конвейеров, чтобы обеспечить их надежность и корректность.
- Логирование и мониторинг конвейеров для отслеживания процесса выполнения и быстрой идентификации проблем.
- Использование переменных сред для хранения конфиденциальных данных, таких как ключи API или пароли. Необходимо хранить такие переменные в безопасном месте и передавать их безопасным способом.
- Поддержание документации для конвейеров, объясняя цели, шаги, настройки и параметры. Это помогает новым членам команды быстро интегрироваться в существующие процессы.
Следуя перечисленным принципам, команда разработчиков сможет создать гибкие, масштабируемые и легко поддерживаемые универсальные конвейеры для CI/CD, которые обеспечат эффективное управление процессами разработки и развертывания программного обеспечения.
Реализация GitOps
GitOps – это методология управления инфраструктурой и приложениями с использованием системы контроля версий Git. Она позволяет автоматизировать процессы развертывания, обновления и масштабирования инфраструктуры и приложений, основываясь на принципах непрерывной интеграции/непрерывного развертывания (CI/CD) и декларативного описания состояния системы.
На наш взгляд, можно выделить следующие весомые преимущества GitOps:
- Унификация и стандартизация. GitOps помогает создать единый и стандартизированный подход к управлению инфраструктурой и приложениями в разных средах.
- Прозрачность. Системы GitOps обеспечивают прозрачность внесенных изменений и текущего состояния системы, что упрощает отслеживание и анализ.
- Автоматизация. GitOps автоматизирует процессы развертывания и обновления, уменьшая человеческий фактор и риск человеческих ошибок.
- Аудит и безопасность. так как все изменения отслеживаются в Git, это облегчает аудит и обеспечивает контроль над безопасностью системы.
- Откат и восстановление. В случае сбоев или ошибок GitOps позволяет быстро вернуть систему к предыдущему стабильному состоянию.
- Воспроизводимость. Декларативное описание позволяет легко воссоздать инфраструктуру и приложения в другой среде.
GitOps применяется в различных областях, включая управление Kubernetes кластерами, инфраструктурой в облаке, приложениями на разных платформах и т. д. Эта методология помогает ускорить и упростить процессы разработки и развертывания, делая их более предсказуемыми и надежными.
Мониторинг и логирование
Построение эффективной системы мониторинга для приложения и инфраструктуры является ключевой составляющей успешной DevOps практики. Это позволяет быстро обнаруживать и реагировать на проблемы, улучшать производительность и обеспечивать стабильность системы. При создании мониторинга, на наш взгляд, необходимо придерживаться ряда принципов:
- Определять, какие аспекты приложения и инфраструктуры наиболее интересны для команды и разработчика. Это может быть доступность, производительность, использование ресурсов, ошибки, логи и другие параметры.
- Выбирать подходящие инструменты для мониторинга, такие как Prometheus, Grafana, Datadog, New Relic и другие. Оценивать их функциональность, интеграцию с технологиями и удобство использования.
- Определять ключевые метрики для каждого аспекта. Например, для приложения это может быть скорость ответов, количество запросов, ошибки, а для инфраструктуры – загрузка CPU, использование памяти, сетевой трафик и др.
- Добавлять код и конфигурацию, необходимые для сбора метрик. Это может включать в себя внедрение кода для сбора пользовательских метрик, настройку агентов для сбора данных о системе и другие шаги.
- Разворачивать выбранные инструменты в инфраструктуре и настраивать их для сбора и визуализации данных.
- Настраивать уведомления, чтобы система могла автоматически оповещать разработчика о проблемах через разные каналы (электронная почта, Slack, SMS и т.д.).
- Создавать графики и дашборды для визуализации собранных данных. Это поможет быстро оценить текущее состояние системы.
- Не перегружать метриками, поскольку это может привести к информационному шуму. Необходимо учитывать важность сбора релевантных данных, сосредотачиваться на том, что действительно важно для понимания и поддержания работы системы.
- Обеспечивать мониторинг логов приложения и инфраструктуры. Это позволит быстро выявлять проблемы и анализировать их причины.
- Постоянно анализировать данные, обновлять метрики и алерты на основе новых данных и изменений в системе.
- Разрабатывать автоматические скрипты или процессы реагирования на события мониторинга, такие как автоматический откат в случае сбоев или масштабирование ресурсов при росте нагрузки.
- Периодически оценивать эффективность мониторинга, добавлять новые метрики и анализировать результаты, чтобы мониторинг соответствовал текущим потребностям.
Мониторинг – это постоянный процесс, который должен эффективно интегрироваться в DevOps практику разработчика. Мониторинг поддерживает надежность и стабильность работы приложения и инфраструктуры, а также обеспечивает своевременное выявление и разрешение проблем.
Откат при обнаружении проблем
Необходимо предусматривать автоматическую остановку развертывания, если мониторинг выявит серьезные проблемы. Это требует создания механизмов автоматического отката (rollback) в случае возникновения проблем после развертывания. Это позволит быстро возвращаться к предыдущему работающему состоянию, если в новой версии приложения или инфраструктуры возникают непредвиденные проблемы. В числе значимых механизмов автоматического отката можно выделить:
- Канареечные релизы (Canary Releases): вместо того чтобы развертывать новую версию приложения сразу на всех серверах или устройствах, она выпускается в ограниченной «канареечной» группе, которая представляет небольшую часть пользователей. Если в новой версии обнаружатся проблемы, разработчик может автоматически откатиться к предыдущей версии и расследовать проблему, не затрагивая всех пользователей
- Двухстороннее развертывание (Blue-Green Deployment): при использовании модели blue-green развертывания у разработчика есть две отдельные среды: «голубая» (blue) и «зеленая» (green). Новая версия разворачивается в «зеленой» среде, а затем переключается трафик с текущей «голубой» среды на «зеленую». Если возникают проблемы, разработчик может вернуть трафик на «голубую» среду, осуществив автоматический откат.
- Автоматический откат на предыдущую версию: В случае, если процесс развертывания или автоматические проверки выявляют проблемы, система может автоматически откатиться к предыдущей версии приложения или инфраструктуры.
- Сохранение бэкапов: перед развертыванием новой версии необходимо создать бэкап текущего состояния. Если возникнут проблемы, система может восстановить предыдущее состояние из бэкапа.
- Тестирование сценариев отката: перед развертыванием новой версии, система может провести тестирование сценариев отката, чтобы убедиться, что процедуры отката работают корректно.
- Мониторинг и автоматическая реакция: Механизмы мониторинга могут автоматически определять аномалии и проблемы в новой версии после развертывания. Если проблема обнаружена, система может автоматически активировать механизм отката.
- Управление состоянием: если конфигурация используется как код, доступно восстановление предыдущей версии конфигурации из Git и пересоздание ресурсов с предыдущей настройкой.
- Планирование отката: CI/CD конвейер может включать шаги для автоматического отката в случае сбоя. Это может включать в себя восстановление базы данных, восстановление образов контейнеров и т. д.
- Логирование и аудит: логирование и аудит событий после развертывания позволяют быстро обнаруживать и анализировать проблемы, что помогает более эффективно проводить откаты при необходимости.
Механизм автоматического отката выбирается в зависимости от потребностей продукта, инфраструктуры и процессов разработки. Важно, чтобы механизмы отката были хорошо протестированы и настроены, чтобы обеспечить надежное и оперативное восстановление в случае проблем.
Управление доступом
Важным этапом становится контроль за доступ к системам CI/CD и целевым окружением, что позволяет предотвратить несанкционированные изменения. Для управления доступом рекомендуется:
- Использовать однозначную идентификацию для всех участников-разработчиков команд.
- Применять механизмы аутентификации, такие как пароли, множественные факторы аутентификации (MFA) и SSH-ключи, для обеспечения безопасности доступа.
- Предоставлять пользователям только те разрешения, которые им необходимы для выполнения своих задач.
- Группировать пользователей с общими потребностями, чтобы управлять доступом более эффективно.
- Определять роли в соответствии с функциональностью и обязанностями пользователей.
- Периодически просматривать и обновлять права доступа пользователей и групп.
- Удалять или ограничивать доступ после выполнения поставленных задач.
Все перечисленные практики позволяют сократить риски несанкционированных изменений и служат эффективным способом управления доступом.
Коллаборация и обратная связь
Процесс CI/CD предполагает постоянное взаимодействие между командами, начиная с интеграции кода и завершая развертыванием в окружениях. Коммуникация осуществляется через установленные каналы связи, такие как совещания, чаты и системы управления задачами. Поддержание открытой коммуникации способствует выявлению и решению проблем на ранних этапах разработки, что влияет на уменьшение времени отклика и повышение эффективности.
Регулярные обсуждения, ретроспективы и совместные совещания способствуют выявлению узких мест в процессе, а также возможностей для улучшения. Обратная связь от команд тестирования и эксплуатации может помочь в определении качества кода и его совместимости с окружением. Это позволяет создать совместное рабочее окружение, в котором каждая команда может внести вклад в достижение общих целей, улучшая качество и скорость разработки.
Постоянное совершенствование
Внедрение CI/CD – это постепенный процесс, который может потребовать настройки и оптимизации для конкретной ситуации. Ключевое значение имеет автоматизация, безопасность и обратная связь, которые помогут улучшить качество разработки и доставки программного обеспечения. Внедрение непрерывных улучшений в CI/CD процессы требует проведения детального анализа и учета раннего опыта.
Заключение
Таким образом, по итогам проведенного исследования была осуществлена разработка методики построения непрерывной интеграции и непрерывного развертывания (СI/CD) для задач подготовки программного обеспечения (ускорения разработки и доставки ПО). Методика основана на сочетании ключевых практик и реализации принципов при построении СI/CD. Полученные результаты исследования имеют прикладное значение с точки зрения организации деятельности DevOps-инженера и служат эффективным инструментом оптимизации деятельности команд разработчиков программного обеспечения. Считаем, что предложенные практики являются достаточно инвариантными и универсальными. Это определяет перспективы их результативного применения в деятельности различных команд с различной спецификой и требованиями к разработке программных продуктов. Ограничения результатов исследования связаны с частичным сохранением необходимости отслеживания влияния использования предложенных практик на эффективность процесса разработки программного обеспечения, что связано с наличием возможных специфичных задач, при которых предложенные практики продемонстрируют относительно меньшую эффективность, нежели другие. Тем не менее обширная практика автора настоящего исследования, а также научно-исследовательский опыт других авторов демонстрируют высокую значимость раскрытой методики и её положительное влияние на скорость разработки и доставки программного обеспечения.