Сегодня мы поговорим про CI/CD — про то, как код доходит до продакшна и почему этот процесс стал таким важным в современной разработке. Раньше выкатка кода в production была сложной, долгой, часто требовала остановки сервиса или объявления технических работ. Релиз превращался в набор ручных операций с высоким риском ошибки. CI/CD нужен, чтобы автоматизировать путь от разработки до продакшена. Смысл в том, чтобы собирать артефакт, проверять его на разных стадиях и доставлять в продакшн по заранее настроенному процессу. До появления этих подходов было много ручной рутины: сборки делали вручную, копировали файлы вручную, ставили на серверы вручную. Это замедляло релизы и увеличивало вероятность ошибок. Теперь разберёмся с расшифровкой. CI/CD — это Continuous Integration и Continuous Delivery или Continuous Deployment. Первая часть, CI, отвечает за автоматическую интеграцию изменений: сборку кода, первичное тестирование. Непрерывная интеграция — это у нас сборка и первичное тестирование. Это может быть не один тест, а несколько: сначала проверка во время сборки, потом дополнительные тесты после. Continuous Delivery и Continuous Deployment — это разные вещи, хотя обе сокращаются как CD. Continuous Delivery означает, что весь путь автоматизирован, но финальный деплой на production делается вручную. Continuous Deployment, наоборот, предполагает полностью автоматический выкат в production. Для крупных и высококритичных систем это менее безопасно — чем критичнее система, тем осторожнее с автоматизацией прода. Continuous Delivery — это когда мы берём результат нашего CI и везём его куда-нибудь. Continuous Deployment — это когда у нас и выкатка в прод тоже автоматизирована. Перейдём к пайплайнам. Типичная схема CI/CD: код коммитится, начинается билд, прогоняются юнит-тесты, интеграционные тесты, артефакт деплоится в стейджинг и потом в production. Для примера возьмём GitLab. Код коммитится, запускается сборка, на CI-этапе проходят unit-тесты и integration tests, потом пайплайн переходит в CD и выкатывает артефакт в staging. Важное свойство таких схем — наличие промежуточных тестовых стендов: acceptance-тесты, интеграционные тесты, smoke-тесты. Если система состоит из нескольких сервисов, надо проверять не только каждый отдельно. Пайплайны могут быть и очень простыми, и очень сложными. В простейшем виде это последовательность «протестировали — сбилдили — задеплоили». В сложном — много этапов, сред, ручных проверок. Идея CI/CD оказалась настолько удобной, что её стали переносить в другие области. Например, MLOps — то же самое, но вместо обычного артефакта рассматривается модель машинного обучения. Для MLOps логика похожая: модель циклически обучают, упаковывают как артефакт, хранят в виде образа или вольюма и автоматически деплоят. Процесс остаётся тем же — итерационная доставка. Пайплайны — это не только практика, но и код. Описание того, как артефакт проходит свой путь, хранится в репозитории. Поэтому Git и стратегия ветвления становятся критически важными. Стратегия ветвления — это набор правил о том, как команда разрабатывает ПО, как пушит изменения, как интегрируется в общую ветку и как готовится релиз. Самая простая стратегия — OneBranchFlow, когда всё идёт в одну ветку. Подходит для маленьких личных проектов или ботов, где нет строгих требований к релизам. GitFlow — одна из самых популярных схем. Есть стабильная ветка Main, которая хранит самый актуальный stable-код, но активно не используется. Основная рабочая ветка — Develop. У нас есть ветка Main, которая содержит самый актуальный код из возможных. Но, тем не менее, этот Main мы никак не используем вообще — он только для релизов. Когда мы видим, что какое-то супер мелкое изменение нужно срочно закатить — в таких случаях существует сущность hotfix. Она создаётся прямо от main и быстро возвращается обратно. Среди плохих практик — пушить всё в один main без веток, использовать бессмысленные коммит-месседжи вроде test, debug, final try. Это ухудшает читаемость истории. Мы стараемся коммитить более часто и более мелкими коммитами. Большой коммит, который копился весь день, плохо читается, плохо откатывается и неудобен для CI/CD. Не забывать делать ребейс — если вы отвели ветку, и пока вы там работали, основная ветка убежала, то всегда хорошим тоном считается ребейзинг перед merge. Если логины и пароли однажды попали в Git, они остаются в истории навсегда. Поэтому игнорирование секретов через gitignore и правильная настройка репозитория критически важны. Самый простой деплой, который существует, это, в общем-то, просто деплой. Обновили сервисы до новой версии, и если что-то сломалось, узнаем об этом только после выкладки. Похожий вариант — частичное обновление, когда не весь набор сервисов выкатывается сразу, а по очереди. Помогает уменьшить риск, но не даёт полноценной защиты от ошибок. Blue-Green Deploy. У нас есть две идентичные среды, или два «плеча». Одно плечо в каждый момент времени простаивает, а другое обслуживает трафик. Сначала обновляют простаивающее плечо. Можно мгновенно откатить, если вы переключили, что-то пошло не так, быстренько откатили обратно на плечо, которое ещё не обновилось. Минус Blue-Green — высокая стоимость: нужно держать две полные копии прода, причём одна всё время простаивает. Поэтому используют в критичных инфраструктурах, где важен быстрый rollback. Canary-деплой похож на Blue-Green, но более гибкий и дешёвый. Не обязательно иметь целое второе плечо: достаточно поднять новую версию сервиса рядом со старой и постепенно перенаправлять трафик. Идея в чём? Что мы можем просто поднять рядом вторую версию сервиса и переключать трафик. Например, сначала 25% пользователей идут на новую версию, а 75% остаются на старой. Главное преимущество Canary — низкий риск: система тестируется на реальных пользователях, но только на малой доле трафика. При проблеме откатить можно быстро. Feature flags — более точечный механизм. Внутри одного и того же кода включают или выключают функции через флаги. Удобно, когда физически невозможно держать две копии сервиса. Rolling update — реплики обновляются по очереди, старая и новая версии сосуществуют, а трафик на новую версию пускается только после успешных проверок. Для этого приложения должны быть stateless.