Хороший конвейер CI/CD — это разница между командой, которая выкатывает десять раз в день и даже не задумывается об этом, и командой, которая две недели готовится к релизу, чтобы завалить его вечером в пятницу. В современной веб-разработке CI/CD перестал быть задачей отдела эксплуатации; это базовая компетенция разработчика. Каждый в команде должен понимать, как работает конвейер, почему он настроен именно так и как его чинить, когда он ломается.
Это руководство о том, как собрать конвейер под современную веб-разработку: достаточно быстрый, чтобы не тормозить разработчиков, достаточно надёжный, чтобы зелёная сборка не была редкостью, и достаточно безопасный, чтобы случайно не наломать дров. Мы разберём разработку в общей ветке, стратегию сред, этапы конвейера и инструменты, которыми это делают в 2026 году.
Разработка в общей ветке
Разработка в общей ветке — фундамент быстрого CI/CD. Принцип прост: каждый разработчик вливается в основную ветку по нескольку раз в день. Никаких долгоживущих веток, никакого ада слияний после двух недель работы. Флаги функций заменяют ветки как механизм изоляции незавершённой работы от продакшена. Основная ветка всегда пригодна к выкладке.
# Every commit to main triggers the full pipeline
# Feature flags gate unfinished work
# Feature flag: new-checkout-flow
if flags.isEnabled("new-checkout-flow"):
return NewCheckoutFlow()
else:
return LegacyCheckoutFlow()
# No long-lived branches needed
# Feature is hidden behind flag until ready
# When ready: flip flag, monitor, remove old codeБольше всего сопротивляются такому подходу команды, у которых нет флагов функций. Без флагов незавершённый код в основной ветке — это риск. С флагами — нет. Вложитесь в систему флагов (LaunchDarkly, Unleash или простое собственное решение) прежде, чем переходить на разработку в общей ветке. Флаги отделяют выкладку от релиза: код можно выкатывать когда угодно, а включать — когда вы готовы.
Этапы конвейера
Современный конвейер состоит из нескольких последовательных этапов, каждый из которых отсеивает свой класс ошибок. Сборка останавливается на первом упавшем этапе, чтобы не жечь вычислительное время впустую. Цель — пройти путь от коммита до продакшена за десять минут, не ради красоты, а потому что быстрая обратная связь удваивает продуктивность.
# Pipeline stages (in order)
# Each stage gates the next
# Stage 1: Lint & format
- name: lint
run: pnpm lint && pnpm format:check
# Stage 2: Type check
- name: typecheck
run: pnpm typecheck
# Stage 3: Unit tests
- name: test
run: pnpm test -- --coverage
# Stage 4: Build
- name: build
run: pnpm build
# Stage 5: Integration tests
- name: integration
run: pnpm test:e2e
# Stage 6: Deploy to staging
- name: deploy-staging
run: ./deploy staging
# Stage 7: Deploy to production (manual approval or auto)
- name: deploy-production
if: github.ref == 'refs/heads/main'
run: ./deploy production
# Stage 8: Post-deploy checks
- name: smoke-tests
run: ./smoke-test productionУ каждого этапа своя ясная цель. Линтер и форматирование ловят стилистические огрехи. Проверка типов отсекает ошибки типов, пока они не стали ошибками времени выполнения. Модульные тесты проверяют логику. Сборка подтверждает, что бандл вообще собирается. Интеграционные тесты проверяют систему целиком. Выкладка на стенд даёт место для ручных и автоматических проверок до продакшена. После продакшена дымовые тесты подтверждают, что выкладка действительно сработала.
- Независимые этапы (линтер, проверка типов, модульные тесты) должны идти параллельно, а не последовательно — это сокращает общее время.
- Кешируйте зависимости и артефакты сборки между прогонами, чтобы не тратить время на повторную загрузку node_modules.
- Дорогие этапы (интеграционные и сквозные тесты) запускайте только после того, как прошли дешёвые.
Стратегия сред
Несколько сред необходимы, но каждая стоит денег. Классическая тройка (разработка, стенд, продакшен) — хорошая отправная точка, но большинству команд нужны нюансы. Среда предпросмотра, создаваемая автоматически под каждую ветку или пул-реквест, позволяет проверить изменения до вливания в основную ветку. Это особенно ценно для правок интерфейса, где одного ревью кода не хватает, чтобы оценить визуальный результат.
# Preview deployments - ephemeral environments per PR
name: Preview
on: pull_request
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pnpm install
- run: pnpm build
- run: ./deploy preview --name pr-${{ github.event.number }}
# Production rollout - gradual (canary)
- name: canary
run: ./deploy-production --canary 10%
- name: observe
run: ./wait-for-observability --timeout 300
- name: full-rollout
if: success()
run: ./deploy-production --canary 100%
- name: rollback-on-failure
if: failure()
run: ./rollback-productionКанареечные выкладки — самый безопасный способ довести код до продакшена. Небольшая доля трафика (скажем, 10%) идёт на новую версию. Если за период наблюдения метрики держатся, доля поднимается до 100%. Если метрики проседают, происходит автоматический откат. Ключ здесь — качественные метрики: доля ошибок, задержка, бизнес-показатели, а не только код состояния HTTP. Страница может вернуться со статусом 200 и всё равно быть сломанной.
Скорость конвейера
Скорость конвейера — не роскошь, а необходимое условие продуктивности. Разработчик, который ждёт сборку тридцать минут, переключает контекст и теряет нить. Разработчик, который ждёт пять, остаётся в коде. Оптимизация времени конвейера — одно из самых выгодных вложений команды: каждая убранная минута умножается на число коммитов в день.
Самый большой выигрыш даёт кеширование. node_modules стоит кешировать между прогонами, пока не изменился package.json. Кеши сборки фреймворка должны сохраняться. Образы Docker должны использовать кеширование слоёв. Второй по величине выигрыш — параллелизация: линтеру и модульным тестам не нужен готовый результат сборки, значит, они идут параллельно. Интеграционным тестам собранная система нужна — они ждут.
Безопасность конвейера
Конвейеры CI/CD — привлекательная цель для атакующих, потому что у них есть доступ к продакшену. Защищать конвейер так же важно, как защищать код приложения: скомпрометированный исполнитель способен внедрить код в ваш продакшен так, будто это сделали вы.
- Используйте OpenID Connect для доступа к облачному провайдеру. Никаких долгоживущих секретов: токен выдаётся на один прогон и истекает по его завершении.
- Подписывайте артефакты сборки. Убедитесь, что выкатывается ровно то, что было собрано: подписанный артефакт нельзя тихо подменить.
- Сканируйте зависимости прямо в конвейере. npm audit, Snyk или Trivy должны ронять сборку при известных уязвимостях в новых зависимостях.
- Держите срок жизни секретов конвейера коротким. Токен должен быть действителен только на время прогона и давать доступ только к нужным ресурсам.
Безопасность не обязана замедлять конвейер. Сканирование зависимостей быстрое и параллелится. OIDC снимает ручную ротацию секретов. Подпись артефактов настраивается один раз. Самый безопасный конвейер — тот, который автоматизирует проверки безопасности, а не полагается на ручной контроль.
Наблюдение и откат
Хороший конвейер не заканчивается выкладкой. Он наблюдает за ней и имеет ясный механизм отката, если что-то пошло не так. Откат должен быть автоматическим, а не ручным. Ждать, пока кто-то заметит, что сайт сломан, и начнёт нажимать кнопки, — значит терять минуты, которые пользователям кажутся часами.
Автоматическому откату нужны ясные критерии. Если доля ошибок выросла на 5% в течение пяти минут после выкладки — откат. Если задержка на 95-м процентиле выросла на 50% — откат. Эти пороги должны быть заданы в инструменте выкладки, а не в чьей-то голове. И каждый откат должен приводить к разбору или хотя бы к уведомлению: вы хотите знать, почему это случилось и как этого избежать.
Конвейеры CI/CD — необходимая инфраструктура современной веб-разработки. Хороший конвейер делает выкладку скучной, и скука здесь — цель. Если каждый ваш коммит приносит сюрпризы, конвейер своего назначения не выполняет.