← назад к разделу

Раньше выпуск новой версии выглядел так: разработчик дописывал код, передавал его «команде релиза», та вручную собирала, тестировала и через несколько дней или недель деплоила на сервер. Если что-то шло не так — разбирались долго, ошибались ещё раз.

CI/CD — это автоматический конвейер, в котором каждый коммит проходит один и тот же путь от изменения до прода. Человек в этом процессе принимает решения («мержим?», «выкатываем?»), а не выполняет руками каждый шаг.

Из чего состоит конвейер

Конвейер — это цепочка стадий. Каждая стадия либо пропускает изменение дальше, либо останавливает его. Частично-зелёного результата нет: либо хорошо, либо стоп.

commit → build → быстрые проверки → медленные проверки → артефакт → staging → verify → прод
         сборка   unit, линт          интеграционные       образ      авто      smoke

Имена стадий у каждой команды свои, но логика одна: чем дороже стадия по времени — тем позже в цепочке.

Артефакт собирается один раз

Самая частая ошибка: собирать код заново для каждого окружения. «Для staging — эта сборка, для прода — соберём ещё раз, уже правильно».

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

Правильный подход называется build once, deploy many: образ собирается один раз на коммит и помечается его хешем (SHA). Именно этот образ едет и в staging, и в прод. Различия между окружениями — только в конфигурации снаружи (переменные окружения, секреты, адреса баз данных), но не в самом артефакте.

Быстрое — раньше медленного

Представьте, что компиляция и базовые тесты занимают 2 минуты, а интеграционные — 30. Если запускать всё вместе, при ошибке в компиляции разработчик узнает об этом через 32 минуты, хотя мог через 2.

Принцип fail fast: самые быстрые проверки идут первыми.

  • Компиляция и unit-тесты — минуты. Их запускают сразу.
  • Интеграционные тесты — десятки минут. Только если быстрые прошли.
  • Деплой на staging и smoke-тесты — после интеграционных.

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

Конвейер описан в коде

Плохой вариант: конвейер настроен кликами в веб-интерфейсе CI-системы. Никто не помнит точно, как он устроен. Его нельзя откатить, сложно воспроизвести на другой машине, невозможно рецензировать в pull request.

Хороший вариант — pipeline as code: конвейер описан файлом в репозитории рядом с кодом. В GitHub Actions это .github/workflows/, в GitLab — .gitlab-ci.yml, в Jenkins — Jenkinsfile. Этот файл версионируется, рецензируется и откатывается так же, как и любой другой код.

Зелёный main — основа командной работы

Если main сломан, никто в команде не может ни собраться, ни задеплоиться. Работа стоит.

Отсюда несколько правил:

  • Прямые пуши в main закрыты. Только через pull request.
  • PR мержится только тогда, когда конвейер зелёный.
  • Если main всё же сломался — чиним немедленно и в приоритете. Откат сломанного коммита (revert) быстрее расследования. Разбираться можно после.

Команда, у которой main красный неделями, по факту не имеет CI: у неё есть сервер, который красиво показывает, что всё сломано.

Деплой и релиз — это разные вещи

Многие боятся деплоить часто, потому что деплой = «пользователи сразу видят новое». Если что-то сломается — страшно.

Но деплой и релиз можно разделить:

  • Деплой — технический шаг: новый код оказался на сервере.
  • Релиз — продуктовый шаг: функция стала доступна пользователям.

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

Это снимает главный страх: деплоить можно часто и спокойно. Релизить — когда готова функция с точки зрения продукта, а не когда «собрался смелости».

Окружения должны быть одинаковыми

Staging (тестовое окружение) нужен именно для того, чтобы проверить то, что поедет в прод. Если staging устроен иначе — он проверяет что-то другое.

Частые причины расхождения:

  • На staging — Docker, на проде — руками на сервере.
  • Разные версии баз данных или промежуточного программного обеспечения.
  • Конфигурация staging «примерно как в проде, но вручную».

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

Конвейер — это тоже система, которую поддерживают

Конвейер — не фоновый процесс, о котором никто не думает. У него есть:

  • Доступность: если CI лежит, команда стоит.
  • Секреты: токены и ключи хранятся правильно, не в открытом тексте.
  • Время выполнения: замедление конвейера — сигнал, что что-то пошло не так.
  • Стоимость: длинные параллельные конвейеры стоят денег.

Конвейер мониторится, его сбои разбираются так же, как инциденты в продакшне.

Частые ошибки

ОшибкаЧто происходитКак правильно
Пересборка артефакта для продаНа прод едёт не то, что тестировалосьСобрать один раз, пометить SHA
Конвейер 40+ минутРазработчики пушат пачками, CI как формальностьБюджет ~15 мин; параллелизм, кеши
Конвейер настроен кликами в UIНевозможно воспроизвести и рецензироватьФайл в репозитории
Красный main «потом починим»Команда заблокированаОткат немедленно, разбор после
Релиз = деплойСтрах деплоев, ночные релизные окнаFeature flags: деплоить часто, релизить осознанно
Staging «почти как прод»Проверяется не то, что поедетОдинаковые декларации, разный конфиг
Ручные шаги между стадиями«Забыл накатить миграцию»Весь путь автоматизирован

Коротко

  • CI/CD — автоматический конвейер: один и тот же путь от коммита до прода для каждого изменения.
  • Build once, deploy many: артефакт собирается один раз и едет в staging и прод без пересборки.
  • Быстрые проверки идут раньше медленных — так ошибка обнаруживается как можно скорее.
  • Конвейер описан файлом в репозитории, рецензируется и версионируется вместе с кодом.
  • Зелёный main — приоритет команды: сломанный откатывается немедленно.
  • Деплой и релиз разделены: новый код едет в прод выключенным, включается отдельно через feature flags.
  • Staging и прод поднимаются из одних деклараций — различается только конфигурация.
  • Конвейер мониторится и поддерживается как любая другая система.

Что почитать дальше

  • CI для Java/Spring: сборка, тесты, quality gates — конкретные шаги конвейера для Java-проекта.
  • Стратегии релиза — что происходит после деплоя на прод.
  • Ветки и релизный цикл — как устроен workflow, который питает конвейер.