где хранится код проекта для непрерывной интеграции
Что такое CI/CD? Разбираемся с непрерывной интеграцией и непрерывной поставкой
В преддверии старта курса «CI/CD на AWS, Azure и Gitlab» подготовили для вас перевод полезного материала.
Непрерывная интеграция (Continuous Integration, CI) и непрерывная поставка (Continuous Delivery, CD) представляют собой культуру, набор принципов и практик, которые позволяют разработчикам чаще и надежнее развертывать изменения программного обеспечения.
CI/CD — это одна из DevOps-практик. Она также относится и к agile-практикам: автоматизация развертывания позволяет разработчикам сосредоточиться на реализации бизнес-требований, на качестве кода и безопасности.
Определение CI/CD
Непрерывная интеграция — это методология разработки и набор практик, при которых в код вносятся небольшие изменения с частыми коммитами. И поскольку большинство современных приложений разрабатываются с использованием различных платформ и инструментов, то появляется необходимость в механизме интеграции и тестировании вносимых изменений.
С технической точки зрения, цель CI — обеспечить последовательный и автоматизированный способ сборки, упаковки и тестирования приложений. При налаженном процессе непрерывной интеграции разработчики с большей вероятностью будут делать частые коммиты, что, в свою очередь, будет способствовать улучшению коммуникации и повышению качества программного обеспечения.
Непрерывная поставка начинается там, где заканчивается непрерывная интеграция. Она автоматизирует развертывание приложений в различные окружения: большинство разработчиков работают как с продакшн-окружением, так и со средами разработки и тестирования.
Инструменты CI/CD помогают настраивать специфические параметры окружения, которые конфигурируются при развертывании. А также CI/CD-автоматизация выполняет необходимые запросы к веб-серверам, базам данных и другим сервисам, которые могут нуждаться в перезапуске или выполнении каких-то дополнительных действий при развертывании приложения.
Непрерывная интеграция и непрерывная поставка нуждаются в непрерывном тестировании, поскольку конечная цель — разработка качественных приложений. Непрерывное тестирование часто реализуется в виде набора различных автоматизированных тестов (регрессионных, производительности и других), которые выполняются в CI/CD-конвейере.
Зрелая практика CI/CD позволяет реализовать непрерывное развертывание: при успешном прохождении кода через CI/CD-конвейер, сборки автоматически развертываются в продакшн-окружении. Команды, практикующие непрерывную поставку, могут позволить себе ежедневное или даже ежечасное развертывание. Хотя здесь стоит отметить, что непрерывная поставка подходит не для всех бизнес-приложений.
Непрерывная интеграция улучшает коммуникации и качество
Непрерывная интеграция — это методология разработки, основанная на регламентированных процессах и автоматизации. При внедренной непрерывной интеграции разработчики часто коммитят свой код в репозиторий исходного кода. И большинство команд придерживается правила коммитить как минимум один раз в день. При небольших изменениях проще выявлять дефекты и различные проблемы, чем при больших изменениях, над которыми работали в течение длительного периода времени. Кроме того, работа с короткими циклами коммитов уменьшает вероятность изменения одной и той же части кода несколькими разработчиками, что может привести к конфликтам при слиянии.
Команды, внедряющие непрерывную интеграцию, часто начинают с настройки системы контроля версий и определения порядка работы. Несмотря на то что коммиты делаются часто, реализация фич и исправление багов могут выполняться довольно долго. Для контроля того, какие фичи и код готовы существует несколько подходов.
Многие используют фича-флаги (feature flag) — механизм для включения и выключения функционала в рантайме. Функционал, который еще находится в стадии разработки, оборачивается фича-флагами и развертывается из master-ветки в продакшн, но отключается до тех пор, пока не будет полностью готов к использованию. По данным недавнего исследования 63 процента команд, использующих фича-флаги, говорят об улучшении тестируемости и повышении качества программного обеспечения. Для работы с фича-флагами есть специальные инструменты, такие как CloudBees Rollout, Optimizely Rollouts и LaunchDarkly, которые интегрируются в CI/CD и позволяют выполнять конфигурацию на уровне фич.
Другой способ работы с фичами — использование веток в системе контроля версий. В этом случае надо определить модель ветвления (например, такую как Gitflow) и описать как код попадает в ветки разработки, тестирования и продакшена. Для фич с длительным циклом разработки создаются отдельные фича-ветки. После завершения работы над фичей разработчики сливают изменения из фича-ветки в основную ветку разработки. Такой подход работает хорошо, но может быть неудобен, если одновременно разрабатывается много фич.
Этап сборки заключается в автоматизации упаковки необходимого программного обеспечения, базы данных и других компонент. Например, если вы разрабатываете Java-приложение, то CI упакует все статические файлы, такие как HTML, CSS и JavaScript, вместе с Java-приложением и скриптами базы данных.
CI не только упакует все компоненты программного обеспечения и базы данных, но также автоматически выполнит модульные тесты и другие виды тестирования. Такое тестирование позволяет разработчикам получить обратную связь о том, что сделанные изменения ничего не сломали.
Большинство CI/CD-инструментов позволяет запускать сборку вручную, по коммиту или по расписанию. Командам необходимо обсудить расписание сборки, которое подходит для них в зависимости от численности команды, ожидаемого количества ежедневных коммитов и других критериев. Важно, чтобы коммиты и сборка были быстрыми, иначе долгая сборка может стать препятствием для разработчиков, пытающихся быстро и часто коммитить.
Непрерывное тестирование — это больше, чем автоматизация тестирования
Фреймворки для автоматизированного тестирования помогают QA-инженерам разрабатывать, запускать и автоматизировать различные виды тестов, которые помогают разработчикам отслеживать успешность сборки. Тестирование включает в себя функциональные тесты, разрабатываемые в конце каждого спринта и объединяемые в регрессионные тесты для всего приложения. Регрессионные тесты информируют команду: не сломали ли их изменения что-то в другой части приложения.
Лучшая практика заключается в том, чтобы требовать от разработчиков запускать все или часть регрессионных тестов в своих локальных окружениях. Это гарантирует, что разработчики будут коммитить уже проверенный код.
Регрессионные тесты — это только начало. Тестирование производительности, тестирование API, статический анализ кода, тестирование безопасности — эти и другие виды тестирования тоже можно автоматизировать. Ключевым моментом является возможность запуска этих тестов из командной строки, через веб-хук (webhook) или через веб-сервис и возврат результата выполнения: успешный был тест или нет.
Непрерывное тестирование подразумевает не только автоматизацию, но и интеграцию автоматического тестирования в конвейер CI/CD. Модульные и функциональные тесты могут быть частью CI и выявлять проблемы до или во время запуска CI-конвейера. Тесты, требующие развертывания полного окружения, такие как тестирование производительности и безопасности, часто являются частью CD и выполняются после разворачивания сборок в целевых средах.
CD-конвейер автоматизирует поставку изменений в различные окружения
Непрерывная поставка — это автоматическое развертывание приложения в целевое окружение. Обычно разработчики работают с одним или несколькими окружениями разработки и тестирования, в которых приложение развертывается для тестирования и ревью. Для этого используются такие CI/CD-инструменты как Jenkins, CircleCI, AWS CodeBuild, Azure DevOps, Atlassian Bamboo, Travis CI.
Типичный CD-конвейер состоит из этапов сборки, тестирования и развертывания. Более сложные конвейеры включают в себя следующие этапы:
В более сложном CD-конвейере могут быть дополнительные этапы, такие как синхронизация данных, архивирование информационных ресурсов, установка обновлений и патчей. CI/CD-инструменты обычно поддерживают плагины. Например, у Jenkins есть более 1500 плагинов для интеграции со сторонними платформами, для расширения пользовательского интерфейса, администрирования, управления исходным кодом и сборкой.
При использовании CI/CD-инструмента разработчики должны убедиться, что все параметры сконфигурированы вне приложения через переменные окружения. CI/CD-инструменты позволяют устанавливать значения этих переменных, маскировать пароли и ключи учетных записей, а также настраивать их во время развертывания для конкретного окружения.
Также в CD-инструментах присутствуют дашборды и отчетность. В случае сбоя сборки или поставки они оповещают об этом. При интеграции CD с системой контроля версий и agile-инструментами облегчается поиск изменений кода и пользовательских историй, вошедших в сборку.
Реализация CI/CD-конвейеров с Kubernetes и бессерверными архитектурами
Многие команды, использующие CI/CD-конвейеры в облаках используют контейнеры, такие как Docker, и системы оркестрации, такие как Kubernetes. Контейнеры позволяют стандартизировать упаковку, поставку и упростить масштабирование и уничтожение окружений с непостоянной нагрузкой.
Есть множество вариантов совместного использования контейнеров, инфраструктуры как код и CI/CD-конвейеров. Подробнее изучить это вы можете в статьях Kubernetes with Jenkins и Kubernetes with Azure DevOps.
Архитектура бессерверных вычислений представляет собой еще один способ развертывания и масштабирования приложений. В бессерверном окружении инфраструктурой полностью управляет поставщик облачных услуг, а приложение потребляет ресурсы по мере необходимости в соответствии с его настройками. Например, в AWS бессерверные приложения запускаются через функции AWS Lambda, развертывание которых может быть интегрировано в CI/CD-конвейер Jenkins с помощью плагина.
CI/CD обеспечивает более частое развертывание кода
Итак, подведем итоги. CI упаковывает, тестирует сборки и оповещает разработчиков, если что-то пошло не так. CD автоматически разворачивает приложения и выполняет дополнительные тесты.
CI/CD-конвейеры предназначены для организаций, которым необходимо часто вносить изменения в приложения с надежным процессом поставки. Помимо стандартизации сборки, разработки тестов и автоматизации развертываний мы получаем целостный производственный процесс по развертыванию изменений кода. Внедрение CI/CD позволяет разработчикам сосредоточиться на улучшении приложений и не тратить силы на его развертывание.
CI/CD является одной из DevOps-практик, поскольку направлена на борьбу с противоречиями между разработчиками, которые хотят часто вносить изменения, и эксплуатацией, требующей стабильности. Благодаря автоматизации, разработчики могут вносить изменения чаще, а команды эксплуатации, в свою очередь, получают большую стабильность, поскольку конфигурация окружений стандартизирована и в процессе поставки осуществляется непрерывное тестирование. Также настройка переменных окружения отделена от приложения и присутствуют автоматизированные процедуры отката.
Эффект от внедрения CI/CD-конвейеров можно измерить в виде ключевых показателей эффективности (KPI) DevOps. Такие KPI как частота поставки (deployment frequency), время реализации изменений (change lead time) и среднее время восстановления после инцидента (mean time to recovery) часто улучшаются при внедрении CI/CD с непрерывным тестированием. Однако CI/CD — это лишь один из процессов, который может способствовать этим улучшениям. Есть и другие условия для увеличения частоты поставки.
Для начала работы с CI/CD команде разработчиков и эксплуатации необходимо совместно определиться с технологиями, практиками и приоритетами. Команды должны выработать консенсус в отношении правильных подходов к своему бизнесу и технологиям, чтобы после внедрения CI/CD команда постоянно придерживалась выбранных практик.
Что такое CI (Continuous Integration)
CI (Continuous Integration) — в дословном переводе «непрерывная интеграция». Имеется в виду интеграция отдельных кусочков кода приложения между собой. Чем чаще мы собираем код воедино и проверяем:
Поэтому я расскажу в статье о том, что это такое. Как CI устроен и чем он пригодится вашему проекту. Если вы больше любите видео-формат, можно посмотреть мой ролик на youtube на ту же тему.
Содержание
Что такое CI
CI — это сборка, деплой и тестирование приложения без участия человека. Сейчас объясню на примере.
Допустим, что у нас есть два разработчика — Маша и Ваня. И тестировщица Катя.
Маша пишет код. Добавляет его в систему контроля версий (от англ. Version Control System, VCS). Это что-то типа дропбокса для кода — место хранения, где сохраняются все изменения и в любой момент можно посмотреть кто, что и когда изменял.
Потом Ваня заканчивает свой кусок функционала. И тоже сохраняет код в VCS.
Собрать билд можно вручную, но это лишний геморрой: нужно помнить, что в каком порядке запустить, какие файлики зависят друг от друга, не ошибиться в команде… Обычно используют специальную программу. Для java это Ant, Maven или Gradle. С помощью сборщика вы один раз настраиваете процесс сборки, а потом запускаете одной командой. Пример запуска для Maven:
Это полуавтоматизация — все равно нужен человек, который введет команду и соберет билд «ручками». Допустим, этим занимаются разработчики. Когда Катя просит билд на тестирование, Ваня обновляет версию из репозитория и собирает билд.
Но собрать билд ≠ получить приложение для тестирования. Его еще надо запустить! Этим занимается сервер приложения. Серверы бывают разные: wildfly, apache, jetty…
Если это wildfly, то нужно:
А вот если убрать из этой схемы человека — мы получим CI!
CI — это приложение, которое позволяет автоматизировать весь процесс. Оно забирает изменения из репозитория с кодом. Само! Тут есть два варианта настройки:
Когда CI получило изменения, оно запускает сборку билда и автотесты.
Если сборка провалилась (тесты упали, или не получилось собрать проект), система пишет электронное письмо всем заинтересованным лицам:
Если сборка прошла успешно, CI разворачивает приложение на тестовой машине. И в итоге Катька может тестировать новую сборку!
Да, разумеется, один раз придется это все настроить — рассказать серверу CI, откуда забирать изменения, какие автотесты запускать, как собирать проект, куда его потом билдить… Но зато один раз настроил — а дальше оно само!
Автотесты тоже придется писать самим, но чтож поделать =)
Если на пальцах, то система CI (Continuous Integration) – это некая программа, которая следит за вашим Source Control, и при появлении там изменений автоматически стягивает их, билдит, гоняет автотесты (конечно, если их пишут).
В случае неудачи она дает об этом знать всем заинтересованным лицам, в первую очередь – последнему коммитеру. (с) habr.com/ru/post/352282
Программы CI
Наиболее популярные — Jenkins и TeamCity.
Но есть куча других вариаций — CruiseControl, CruiseControl.Net, Atlassian Bamboo, Hudson, Microsoft Team Foundation Server.
Как это выглядит
Давайте посмотрим, как это выглядит с точки зрения пользователя. Я покажу на примере системы TeamCity.
Когда я захожу в систему, я вижу все задачи. Задачи бывают разные:
Поэтому, даже если я не подписана на оповещения на электронную почту о состоянии сборок, я легко могу посмотреть, в каком состоянии сейчас система. Открываешь графический интерфейс программы и смотришь.
Как CI устроен
Как и где CI собирает билд и прогоняет автотесты? Я расскажу на примере TeamCity, но другие системы работают примерно также.
Сам TeamCity ничего не собирает. Сборка и прогон автотестов проходят на других машинах, которые называются «агенты»:
«Агент» — это простой компьютер. Железка или виртуальная машина, не суть. Но как этот комьютер понимает, что ему надо сделать?
В TeamCity есть сервер и клиент. Сервер — это то самое приложение, в котором вы потом будете тыкать кнопочки и смотреть красивую картинку «насколько все прошло успешно». Он устанавливается на одну машину.
А приложение-«клиент» устанавливается на машинах-«агентах». И когда мы нажимаем кнопку «Run» на сервере:
Сервер выбирает свободного клиента и передает ему все инструкции: что именно надо сделать. Клиент собирает билд, выполняет автотесты, собирает результат и возвращает серверу: «На, держи, отрисовывай».
Сервер отображает пользователю результат плюс рассылает email всем заинтересованным лицам.
При этом мы всегда видим, на каком конкретно агенте проходила сборка:
И можно самому выбирать, где прогонять автотесты. Потому что бывает, что автотесты падают только на одном билд-агенте. Это значит, что у него что-то не так с конфигурацией.
Допустим, исходно у нас был только один билд-агент — Buran. Название может быть абсолютно любым, его придумывает администратор, когда подключает новую машину к TeamCity как билд-агента.
Мы собирали на нем проект, проводили автотесты — все работало. А потом закупили вторую машинку и назвали Apollo. Вроде настроили также, как Буран, даже операционную систему одинаковую поставили — CentOs 7.
Но запускаем сборку на Apollo — падает. Причем падает странно, не хватает памяти или еще чего-то. Перезапускаем на Apollo — снова падает. Запускаем на Буране — проходит успешно!
Начинаем разбираться и выясняем, что в Apollo забыли про какую-то настройку. Например, не увеличили количество открытых файловых дескриптеров. Исправили, прогнали сборку на Apollo — да, работает, ура!
Мы также можем для каждой сборки настроить список агентов, на которых она может выполняться. Зачем? Например, у нас на половине агентов линукс, а на половине винда. А сборку мы только под одну систему сделали. Или на винде вылезает какой-то плавающий баг, но исправлять его долго и дорого, а все клиенты на линуксе — ну и зачем тогда?
А еще бывает, что агентов делят между проектами, чтобы не было драки — этот проект использует Бурана и Аполло, а тот Чип и Дейла. Фишка ведь в том, что на одном агенте может выполняться только одно задание. Поэтому нет смысла покупать под агент крутую тачку, сразу кучу тестов там все равно не прогнать.
В итоге как это работает: сначала админ закупает компьютеры под «агенты» и устанавливает на них клиентское приложение TeamCity. Слишком крутыми они быть не должны, потому что много задач сразу делать не будут.
При этом TeamCity вы платите за количество лицензий на билд-агентов. Так что чем меньше их будет, тем лучше.
На отдельной машине админ устанавливает сервер TeamCity. И конфигурирует его — настраивает сборки, указывает, какие сборки на каких машинах можно гонять, итд. На сервере нужно место для хранения артефактов — результатов выполнения сборки.
У нас есть два проекта — Единый клиент и Фактор, которые взаимодействуют между собой. Тестировщик Единого клиента может не собирать Фактор локально. Он запускает сборку в TeamCity и скачивает готовый билд из артефактов!
Дальше уже разработчик выбирает, какую сборку он хочет запустить и нажимает «Run». Что в этот момент происходит:
1. Сервер TeamCity проверяет по списку, на каких агентах эту сборку можно запускать. Потом он проверяет, кто из этих агентов в данный момент свободен:
Нашел свободного? Отдал ему задачку!
Если все агенты заняты, задача попадает в очередь. Очередь работает по принципу FIFO — first in, first out. Кто первый встал — того и тапки.
Очередь можно корректировать вручную. Так, если я вижу, что очередь забита сборками, которые запустила система контроля версий, я подниму свою на самый верх. Если я вижу, что сборки запускали люди — значит, они тоже важные, придется подождать.
Это нормальная практика, если мощностей агентов не хватает на всей и создается очередь. Смотришь, кто ее запустил:
3. Сервер отрисовывает результат в графическом интерфейсе и сохраняет артефакты. Так я могу зайти в TeamCity и посмотреть в артефактах полные логи прошедших автотестов, или скачать сборку проекта, чтобы развернуть ее локально.
Настоятельно рекомендуется настроить заранее количество сборок, которые CI будет хранить. Потому что если в артефактах лежат билды по 200+ мб и их будет много, то очередной запуск сборки упадет с ошибкой «кончилось место на диске»:
4. Сервер делает рассылку по email — тут уж как настроите. Он может и позитивную рассылку делать «сборка собралась успешно», а может присылать почту только в случае неудачи «Ой-ей-ей, что-то пошло не так!».
Интеграция с VCS
Я говорила о разных вариантах настройки интеграции CI — VCS:
Но когда какой используется?
Лучше всего, конечно, чтобы система контроля версий оповещала сервер CI. И запускать весь цикл на каждое изменение: собрать, протестировать, задеплоить. Тогда любое изменение кода сразу попадет на тестовое окружение, которое будет максимально актуальным.
Плюс каждое изменение прогоняет автотесты. И если тесты упадут, сразу ясно, чей коммит их сломал. Ведь раньше работало и после Васиных правок вдруг сломалось — значит, это его коммит привел к падению. За редким исключением, когда падение плавающее.
Но в реальной жизни такая схема редко применима. Только подумайте — у вас ведь может быть много проектов, много разработчиков. Каждый что-то коммитит ну хотя бы раз в полчаса. И если на каждый коммит запускать 10 сборок по полчаса — очереди в TeamCity никогда не разгребутся!
У нас у одного из продуктов есть core-модуль, а есть 15+ Заказчиков. В каждом свои автотесты. Сборка заказчика — это core + особенности заказчика. То есть изменение в корневом проекте может повлиять на 15 разных сборок. Значит, их все надо запустить при коммите в core.
Когда у нас было 4 билд-агента, все-все-все сборки и тесты по этим заказчикам запускались в ночь на вторник. И к 10 утра в TeamCity еще была очередь на пару часов.
Другой вариант — закупить много агентов. Но это цена за саму машину + за лицензию в TeamCity, что уже сильно дороже, да еще и каждый месяц платить.
Поэтому обычно делают как:
1. Очень быстрые и важные сборки можно оставить на любой коммит — если это займет 1-2 минуты, пусть гоняется.
2. Остальные сборки проверяют, были ли изменения в VCS — например, раз в 15 минут. Если были, тогда запускаем.
3. Долгие тесты (например, тесты производительности) — раз в несколько дней ночью.
CI в тестировании
Если мы говорим о разработке своего приложения, то тестирование входит в стандартный цикл. Вы или ваши разработчики пишут автотесты, которые потом гоняет CI. Это могут быть unit, api, gui или нагрузочные тесты.
Но что, если вы тестируете черный ящик? Приложение есть, исходного кода нету. Это суровые реалии тестировщиков интеграции — поставщик отдает вам новый релиз приложения, который нужно проверить перед тем, как ставить в продакшен.
Вот, допустим, у вас есть API-тесты в Postman-е. Или GUI-тесты в Selenium. Можно ли настроить цикл CI для них?
CI не ставит жестких рамок типа «я работаю только в проектах с автотестами» или «я работаю только когда есть доступ к исходному коду». Он может смотреть в систему контроля версий, а может и не смотреть. Это необязательное условие!
Написали автотесты? Скажите серверу CI, как часто их запускать — и наслаждайтесь результатом =)
Итого
CI — непрерывная интеграция. Это когда ваше приложение постоянно проверяется: все ли с ним хорошо? Проходят ли тесты? Собирается ли сборка? Причем все проверки проводятся автоматически, без участия человека.
Особенно актуально для команд, где над кодом одного приложения трудятся несколько разработчиков. Как это бывает? По отдельности части программы работают, а вот вместе уже нет. CI позволяет очень быстро обнаружить такие проблемы. А чем быстрее найдешь — тем дешевле исправить.
Отсюда и название — постоянная проверка интеграции кусочков кода между собой.
Типичные задачи CI:
И все это — автоматически, без вмешательства человека! То есть один раз настроили, а дальше оно само.
Если в проекте настроен CI, у вас будут постоянно актуальные тестовые стенды. И если в коде что-то сломается, вы узнаете об этом сразу, сервер CI пришлет письмо. А еще можно зайти в графический интерфейс и посмотреть — все ли сборки успешные, а тесты зеленые? Оценить картину по проекту за минуту.
PS — больше полезных статей ищите в моем блоге по метке «полезное». А полезные видео — на моем youtube-канале