Пайплайн CI/CD: от пуша до рабочего сервера
Как проходит пайплайн из восьми задач, чем CI отличается от поставки и развёртывания, быстрый пайплайн за 4 минуты вместо 15, сравнение шести инструментов, четыре способа выкладки, два файла кода, правила и ошибки.
Коротко
Пайплайн CI/CD — это путь, который каждое изменение кода проходит автоматически: линтер, проверка типов и тесты, затем сборка, выкладка на тестовый сервер и на рабочий, а после — наблюдение и откат, если выросли ошибки. CI — непрерывная интеграция — проверяет каждое изменение до того, как его примут в основную ветку. CD — это либо непрерывная поставка, когда релиз готов, а кнопку нажимает человек, либо непрерывное развёртывание, когда всё, что прошло проверки, выходит в работу само. Пайплайн описывают в файле рядом с кодом: на GitHub это GitHub Actions, на GitLab — GitLab CI/CD. Небольшому сайту он заменяет ручную заливку файлов и забытые шаги, а команде даёт выкладывать изменения каждый день, не ломая друг другу работу. Хороший пайплайн проходит меньше чем за десять минут, останавливается на первой упавшей проверке и возвращает прошлую версию за секунды.
Как проходит пайплайн
Восемь задач от пуша до рабочего сервера. Переключите сценарий: всё проходит, падает тест или плохой релиз доходит до рабочего сервера.
- ✓ Пуш git push в main 0:02
- ✓ Линтер стиль и ошибки 0:38
- ✓ Типы tsc --noEmit 0:51
- ✓ Тесты 214 тестов 2:04
- ✓ Сборка npm run build 1:12
- ✓ Тестовый выкладка и проверка 0:46
- ✓ Рабочий выкладка 0:31
- ✓ Наблюдение ошибки, 10 минут 10:00
✓ 214 тестов прошли ✓ тестовый сервер отвечает 200 ✓ выложено: v1.42 → рабочий сервер ✓ ошибок не больше, чем до выкладки
Выкладка прошла сама: от пуша до рабочего сервера — меньше пяти минут, на сервер никто не заходил.
- ✓ Пуш git push в main 0:02
- ✓ Линтер стиль и ошибки 0:38
- ✓ Типы tsc --noEmit 0:51
- ✗ Тесты 214 тестов 1:47
- – Сборка npm run build —
- – Тестовый выкладка и проверка —
- – Рабочий выкладка —
- – Наблюдение ошибки, 10 минут —
✗ checkout.test.ts › скидка не применяется к корзине ожидалось 2 700 ₽, получено 3 000 ₽ — сборка и выкладка пропущены → автору изменения ушло письмо
Пайплайн остановился на тестах. На рабочем сервере осталась прежняя версия, покупатели ошибку не увидели.
- ✓ Пуш git push в main 0:02
- ✓ Линтер стиль и ошибки 0:38
- ✓ Типы tsc --noEmit 0:51
- ✓ Тесты 214 тестов 2:04
- ✓ Сборка npm run build 1:12
- ✓ Тестовый выкладка и проверка 0:46
- ↩ Рабочий выкладка 0:31
- ✗ Наблюдение ошибки, 10 минут 3:20
✓ выложено: v1.42 → рабочий сервер ✗ ошибок 4,1 % при пороге 1 % ↩ возвращена v1.41 за 28 секунд → команде ушло сообщение с журналом
После выкладки выросли ошибки — пайплайн сам вернул прошлую версию. Разбираться можно спокойно, сайт работает.
Ценность пайплайна — в двух плохих сценариях. Упавший тест останавливает выкладку раньше, чем ошибку кто-то увидит, а проскочивший плохой релиз откатывается сам, без ночного звонка. Линтер, типы и тесты идут одновременно — они друг от друга не зависят.
CI, непрерывная поставка и непрерывное развёртывание
Три ступени автоматизации. Каждая опирается на предыдущую.
| Термин | Что автоматизировано | Кто выкладывает | Подходит |
|---|---|---|---|
| Непрерывная интеграция (CI) | линтер, типы, тесты и сборка на каждое изменение | человек, вручную | любой проект, где больше одного разработчика |
| Непрерывная поставка | плюс выкладка на тестовый сервер и готовый релиз для рабочего | человек нажимает одну кнопку | магазины, сервисы с графиком релизов |
| Непрерывное развёртывание | всё, вплоть до рабочего сервера и отката | никто: прошло проверки — вышло в работу | команды с хорошими тестами и наблюдением |
Быстрый пайплайн: 15 минут или 4
Одни и те же задачи, запущенные по-разному. Медленный пайплайн начинают обходить, поэтому скорость — часть надёжности.
Весь прогон14:40
- зависимости каждый раз качаются заново
- проверки ждут друг друга
- все тесты в одном потоке
- сборка с нуля
Весь прогон4:00
- зависимости из кеша
- линтер, типы и тесты — одновременно
- тесты поделены на три части
- сборка берёт неизменённое из кеша
Пример проекта на Node.js; минуты условные, соотношение — типичное.
Сравнение инструментов CI/CD
Бесплатные лимиты — с открытых страниц сервисов, октябрь 2026. Инструмент обычно выбирают по тому, где лежит код.
| Инструмент | Где работает | Бесплатно | Сильная сторона |
|---|---|---|---|
| GitHub Actions | облако GitHub или свой сервер | открытые репозитории и свои раннеры; закрытые — 2 000 минут в месяц, дальше от $0,006 за минуту | тысячи готовых действий, всё рядом с кодом |
| GitLab CI/CD | облако GitLab или свой GitLab | 400 минут в месяц; Premium — 10 000 за $29 на человека | код, задачи и пайплайны в одном месте, можно поставить у себя |
| Bitbucket Pipelines | облако Atlassian | 50 минут в месяц; +1 000 минут за $10 | команды, которые уже работают в Jira |
| CircleCI | облако CircleCI или свой сервер | 30 000 кредитов в месяц — около 3 000 минут, 5 человек | быстрые сборки, параллельные задачи, деление тестов |
| Jenkins | только свой сервер | бесплатный, открытый код; платите за сервер и его обслуживание | полный контроль, большие старые проекты |
| Vercel, Netlify, Cloudflare Pages | собственные платформы | бесплатные тарифы для небольших сайтов | фронтенд выходит на каждый пуш, у каждой ветки своё превью |
Четыре способа выкладки
От последнего шага пайплайна зависит, заметят ли выкладку посетители. Переключите способ: кто какую версию видит и как быстро можно вернуться.
- Простой
- от секунд до минут
- Откат
- выложить старую версию заново
- Подходит
- внутренние сервисы, выкладка ночью
- Простой
- нет
- Откат
- так же по очереди, обратно
- Подходит
- приложения на нескольких серверах
- Простой
- нет
- Откат
- мгновенно — переключить обратно
- Подходит
- сайты и магазины; на одном сервере — две папки и ссылка
- Простой
- нет
- Откат
- ошибку увидит малая доля посетителей
- Подходит
- большая аудитория, рискованные изменения
Сайту на одном сервере не нужен кластер для сине-зелёной выкладки. Новая версия загружается в свою папку, и символическая ссылка переключается на неё одним действием: посетители видят либо старую версию, либо новую, но никогда половину той и другой. Прошлая папка остаётся, поэтому откат — то же переключение обратно; скрипт — ниже.
Что автоматизировать в первую очередь
-
1. Выкладка одним действием
Слияние в основную ветку выкладывает сайт. Никакой заливки руками и «забыл скопировать файл».
-
2. Проверки на каждый запрос на слияние
Линтер, типы и сборка: они ловят большую часть глупых ошибок ещё до проверки коллегой.
-
3. Тесты на деньги и регистрацию
Не стопроцентное покрытие, а корзина, оплата, регистрация и форма заявки.
-
4. Превью до выкладки
Тестовый сервер или превью для каждой ветки: заказчик видит изменение раньше посетителей.
-
5. Проверка после выкладки и откат
Сайт отвечает, ошибок не прибавилось — иначе прошлая версия возвращается сама.
-
6. Обновления зависимостей и проверка уязвимостей
Раз в неделю — запросы на слияние с обновлениями, которые проходят те же проверки.
Пайплайн в коде: 2 файла
Пайплайн GitHub Actions для сайта на своём сервере и скрипт на сервере, который переключает релизы и откатывает.
Проверки, сборка и выкладка
Проверки идут на каждый запрос на слияние, выкладка — только из main и только если все проверки прошли. Ключи хранятся в секретах репозитория, а не в коде.
name: CI/CD
on:
pull_request:
push:
branches: [main]
concurrency: # новый пуш отменяет прогон старого
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm # зависимости из кеша: минуты → секунды
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build
- uses: actions/upload-artifact@v7
with:
name: site
path: dist/
deploy:
needs: checks # упала проверка — выкладки не будет
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production # секреты и, если нужно, ручное подтверждение
steps:
- uses: actions/download-artifact@v8
with:
name: site
path: dist/
- name: Загрузить и переключить
env:
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
KNOWN_HOSTS: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
HOST: ${{ vars.DEPLOY_HOST }}
run: |
mkdir -p ~/.ssh
echo "$SSH_KEY" > ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519
echo "$KNOWN_HOSTS" > ~/.ssh/known_hosts
RELEASE=$(date -u +%Y%m%d%H%M%S)
rsync -az dist/ "deploy@$HOST:/srv/site/releases/$RELEASE/"
ssh "deploy@$HOST" "/srv/site/switch.sh $RELEASE"
Переключить и откатить
Ссылка переключается одним действием, потом скрипт проверяет сайт. Не прошла проверка — возвращается прошлый релиз, а пайплайн становится красным.
#!/bin/sh
# Переключает сайт на новый релиз и возвращает старый, если проверка не прошла
set -eu
SITE=/srv/site
NEW="$SITE/releases/$1"
OLD=$(readlink -f "$SITE/current" || true)
switch_to() {
ln -sfn "$1" "$SITE/current.next"
mv -T "$SITE/current.next" "$SITE/current" # разом: старая или новая
}
switch_to "$NEW"
if ! curl -fsS --max-time 10 https://example.ru/health > /dev/null; then
[ -n "$OLD" ] && switch_to "$OLD"
echo "Проверка не прошла, вернули $(basename "$OLD")" >&2
exit 1
fi
# храним пять последних релизов для быстрого отката
ls -1dt "$SITE"/releases/*/ | tail -n +6 | xargs -r rm -rf
7 правил хорошего пайплайна
-
01
Меньше десяти минут
Кеш, параллельные задачи и деление тестов. Медленный пайплайн начинают обходить.
-
02
Одна сборка на все среды
На тестовый и рабочий сервер уходят одни и те же файлы, отличаются только настройки.
-
03
Секреты — вне кода
Ключи в секретах репозитория, с минимальными правами для своей задачи.
-
04
Стоп на первой красной проверке
Выкладка с упавшим тестом не уходит даже «один разок».
-
05
Миграции, которые переживёт старая версия
Сначала добавить колонку, выложить, потом убрать старую — тогда откат не ломает базу.
-
06
Откат одним действием
Хранить несколько прошлых релизов и проверить откат до того, как он понадобится.
-
07
Сообщение — только когда важно
Красный пайплайн и откат приходят человеку сразу, зелёные прогоны остаются в журнале.
Частые ошибки в CI/CD
-
Нестабильные тесты, которые все перезапускают
Красный прогон перестаёт что-то значить, и вместе с ним проходит настоящая ошибка.
-
Отдельная сборка для рабочего сервера
На тестовом проверили одни файлы, на рабочий ушли другие.
-
Ключи в репозитории
Они остаются в истории даже после удаления файла.
-
Правки руками на сервере
Следующая выкладка их затирает, и никто не помнит, почему ошибка вернулась.
-
Миграция без пути назад
Код можно откатить, а удалённую колонку — нет.
-
Уведомления о каждом зелёном прогоне
Через неделю их никто не читает, включая красные.
Вопросы о CI/CD
Нужен ли CI/CD небольшому сайту?
Да, в самом простом виде: выкладка из основной ветки одним действием и откат. Настраивается за несколько часов и навсегда убирает ручную заливку.
Чем CI отличается от CD?
CI проверяет и собирает каждое изменение. CD доставляет результат на серверы: по кнопке при непрерывной поставке или само при непрерывном развёртывании.
Какой инструмент выбрать?
Встроенный в ваш хостинг кода: GitHub Actions для GitHub, GitLab CI/CD для GitLab. Отдельный инструмент оправдан только при особых требованиях.
Обязателен ли Docker?
Нет. Сайт можно выкладывать папкой файлов с переключением ссылки. Docker помогает, когда сервисов или серверов несколько.
Как выкладывать без простоя?
Готовить новую версию рядом со старой и переключать трафик одним действием: ссылкой на одном сервере, балансировщиком — на нескольких.
Сколько стоит CI/CD?
Большинству небольших проектов хватает бесплатных лимитов: 2 000 минут в месяц на GitHub, 400 на GitLab. Основные затраты — настройка и тесты.
Форма
Выкладка
без страха
Настраиваю пайплайны для сайтов и сервисов: проверки каждого изменения, выкладка в один шаг и откат за секунды. Расскажите о проекте — отвечу в течение рабочего дня.