Антон Ларичев

Введение
CI/CD (Continuous Integration / Continuous Delivery или Deployment) — это набор практик и инструментов для автоматизации сборки, тестирования и доставки кода в продакшн. Вместо того чтобы вручную собирать проект, гонять тесты и заливать файлы на сервер, эти процессы запускает система при каждом пуше в репозиторий.
Continuous Integration (непрерывная интеграция) — это про то, что каждый коммит автоматически собирается и проверяется тестами, чтобы ошибки находились сразу, а не через неделю. Continuous Delivery (непрерывная доставка) добавляет к этому автоматическую подготовку релиза, готового к выкладке одной кнопкой. Continuous Deployment (непрерывное развёртывание) идёт ещё дальше и выкатывает изменения в продакшн без участия человека, если все проверки прошли.
Зачем это нужно
Без CI/CD разработчики тратят время на рутину: ручную сборку, ручной прогон тестов, ручной деплой по инструкции из десяти шагов. Это медленно и подвержено человеческим ошибкам. CI/CD решает три задачи:
- быстрая обратная связь — баг находится за минуты, а не после релиза
- одинаковый процесс для всех — исключается "у меня на компьютере работало"
- ускорение релизов — можно деплоить несколько раз в день без страха
Из чего состоит пайплайн
Типичный CI/CD-пайплайн состоит из последовательных этапов (stages):
- Установка зависимостей
- Линтинг и статический анализ
- Сборка (build)
- Тесты (unit, integration, e2e)
- Публикация артефакта (Docker-образ, архив, npm-пакет)
- Деплой на staging
- Деплой на продакшн (часто вручную подтверждается)
Каждый этап должен быть быстрым и завершаться однозначным статусом success/fail — это ключевое правило: если хоть один шаг падает, пайплайн останавливается и код не попадает дальше.
Настройка CI/CD на примере GitHub Actions
GitHub Actions — один из самых популярных инструментов, потому что не требует отдельного сервера и настраивается прямо в репозитории через YAML-файлы в директории .github/workflows.
Создадим простой пайплайн для Node.js проекта.
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Скачиваем код
uses: actions/checkout@v4
- name: Устанавливаем Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Устанавливаем зависимости
run: npm ci
- name: Линтинг
run: npm run lint
- name: Тесты
run: npm test
Этот файл описывает job test, который запускается на каждый пуш и pull request в main. Триггер on определяет события, jobs — список задач, steps — последовательные шаги внутри задачи.
Добавляем сборку и деплой
После того как тесты проходят, можно добавить job для сборки Docker-образа и деплоя.
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Скачиваем код
uses: actions/checkout@v4
- name: Логинимся в Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Собираем и пушим образ
run: |
docker build -t myapp:${{ github.sha }} .
docker push myapp:${{ github.sha }}
- name: Деплоим на сервер
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull myapp:${{ github.sha }}
docker stop myapp || true
docker run -d --name myapp -p 3000:3000 myapp:${{ github.sha }}
Ключевые моменты здесь: needs: test означает, что деплой запустится только после успешного прохождения тестов. Условие if ограничивает деплой только веткой main. Все пароли и ключи хранятся в secrets репозитория, а не в коде.
Пример для GitLab CI
Если проект на GitLab, конфигурация задаётся файлом .gitlab-ci.yml.
stages:
- test
- build
- deploy
test:
stage: test
image: node:20
script:
- npm ci
- npm run lint
- npm test
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
script:
- ./deploy.sh $CI_COMMIT_SHA
only:
- main
Принцип тот же: этапы идут последовательно, и каждый следующий запускается только если предыдущий завершился успешно.
Частые ошибки
Хранение секретов в коде. Пароли, токены и SSH-ключи нужно класть в secrets CI-системы, а не коммитить в репозиторий, даже во временный файл.
Слишком долгий пайплайн. Если сборка и тесты занимают 30 минут, разработчики начинают игнорировать статус или пушить прямо в обход проверок. Нужно распараллеливать job'ы и кэшировать зависимости.
Отсутствие кэширования зависимостей. Установка npm-пакетов или сборка Docker-слоёв с нуля на каждом запуске сильно замедляет пайплайн — используйте cache в actions/setup-node или кэш слоёв Docker.
Деплой без отката. Если новая версия ломает продакшн, должен быть быстрый путь вернуться к предыдущей версии — через тег предыдущего образа или blue-green деплой.
Игнорирование пайплайна при провале. Красный статус CI должен быть блокером для мержа, а не рекомендацией — настройте branch protection, требующее прохождения проверок.
Тестирование только на staging вручную. Автоматические тесты в пайплайне должны покрывать основные сценарии, иначе staging превращается в ещё один ручной этап, который CI/CD должен был исключить.
Заключение
CI/CD — это не единственный инструмент, а практика, которая объединяет автоматическую сборку, тестирование и доставку кода. Начать можно с малого: настроить job, который гоняет тесты на каждый pull request. Дальше постепенно добавляются сборка Docker-образа, деплой на staging и продакшн, уведомления в Slack и метрики. Главное — держать пайплайн быстрым, безопасным и обязательным для всех изменений в коде.






Комментарии
0