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