Создание системы CI/CD: автоматический деплой кода из Git-репозитория - Компьюти
Logo КОМПЬЮТИ

Создание системы CI/CD: автоматический деплой кода из Git-репозитория

Время на прочтение: 9 мин.

Автоматический деплой позволяет превратить публикацию новой версии сайта или веб-приложения из ручной операции в предсказуемый технический процесс. Разработчик отправляет изменения в Git-репозиторий, после чего система CI/CD автоматически проверяет код, собирает проект и, если все проверки пройдены, разворачивает новую версию на сервере.

Для веб-студии это особенно важно: чем больше проектов находится в работе, тем дороже обходятся ручные деплои, ошибки при переносе файлов и несогласованные действия между разработчиками и DevOps-специалистами.

В этой статье разберём, как спроектировать CI/CD-процесс с нуля, какие компоненты для него нужны, как организовать автоматический деплой из Git и какие ошибки стоит предусмотреть заранее.


Что такое CI/CD

CI/CD — это набор практик и инструментов, которые автоматизируют проверку, сборку и доставку программного обеспечения.

Аббревиатура состоит из нескольких частей:

  • CI (Continuous Integration, непрерывная интеграция) — автоматическая проверка изменений после их добавления в репозиторий.
  • Continuous Delivery (непрерывная доставка) — подготовка приложения к выпуску таким образом, чтобы новая версия могла быть быстро развернута.
  • Continuous Deployment (непрерывное развертывание) — автоматическая публикация изменений на целевом сервере после успешного прохождения всех проверок.

В простом варианте процесс выглядит так:

Разработчик
    ↓
git push
    ↓
Git-репозиторий
    ↓
CI/CD pipeline
    ↓
Проверка кода
    ↓
Тесты
    ↓
Сборка проекта
    ↓
Deploy
    ↓
Production-сервер

Главная идея заключается в том, что человек инициирует изменение, а повторяемые технические операции выполняет автоматизированная система.


Зачем веб-студии нужен CI/CD

На небольшом проекте разработчик может вручную подключиться к серверу, выполнить git pull, установить зависимости и перезапустить приложение. На практике такой подход быстро начинает создавать проблемы.

1. Меньше ручной работы

Вместо последовательности:

ssh server
cd /var/www/project
git pull
npm install
npm run build
pm2 restart app

разработчику достаточно выполнить:

git push

Остальные действия выполняет pipeline.

2. Меньше человеческих ошибок

При ручном деплое легко:

  • забыть установить новую зависимость;
  • собрать проект не из той ветки;
  • изменить конфигурацию сервера;
  • перезапустить не тот процесс;
  • загрузить не все необходимые файлы;
  • выполнить команды в неправильном порядке.

CI/CD превращает процедуру деплоя в заранее описанный сценарий.

3. Единый процесс для всех проектов

Веб-студия может стандартизировать деплой для разных сайтов и приложений.

Например:

push
 ↓
lint
 ↓
test
 ↓
build
 ↓
deploy
 ↓
health check

Новый разработчик не обязан запоминать внутреннюю процедуру публикации каждого проекта.

4. Быстрее выпускать изменения

Если проект настроен правильно, путь от commit до новой версии на сервере может занимать считанные минуты.

5. Появляется история деплоев

Git и CI/CD позволяют определить:

  • какой commit был опубликован;
  • когда произошёл деплой;
  • кто отправил изменения;
  • какие проверки прошли;
  • успешно ли завершился pipeline.

Это значительно упрощает поиск причин проблем.


Из чего состоит CI/CD-система

Типичная инфраструктура включает несколько компонентов.

Git-репозиторий

Например:

  • GitHub;
  • GitLab;
  • Bitbucket.

В репозитории хранится исходный код и конфигурация pipeline.

CI/CD runner

Это сервер или контейнер, который получает задания pipeline и выполняет команды.

Он может:

  • установить зависимости;
  • запустить линтер;
  • выполнить тесты;
  • собрать frontend;
  • создать Docker-образ;
  • подключиться к серверу;
  • выполнить деплой.

Target-сервер

Сервер, на котором работает приложение.

Это может быть:

  • VPS;
  • выделенный сервер;
  • облачная виртуальная машина;
  • Kubernetes-кластер;
  • managed-платформа.

Secrets

Конфиденциальные параметры, необходимые pipeline:

SSH_PRIVATE_KEY
DEPLOY_HOST
DEPLOY_USER
DATABASE_URL
API_TOKEN

Пароли и приватные ключи не должны храниться непосредственно в Git-репозитории.


Какую архитектуру выбрать

Для большинства небольших и средних веб-проектов нет необходимости сразу строить сложную DevOps-инфраструктуру.

Практичная архитектура может выглядеть следующим образом:

                 Git Repository
                       │
                       │ push
                       ▼
                CI/CD Pipeline
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
       Lint          Tests         Build
          │            │            │
          └────────────┼────────────┘
                       ▼
                    Deploy
                       │
                       ▼
                 Production
                    Server
                       │
                       ▼
                 Web application

При этом можно разделить окружения:

feature/*
    ↓
Pull Request
    ↓
CI checks
    ↓
develop
    ↓
staging
    ↓
main
    ↓
production

Такой подход позволяет сначала проверить изменения на staging, а затем публиковать их в production.


Пример стека

Для демонстрации возьмём распространённый вариант:

  • GitHub или GitLab — хранение кода;
  • Ubuntu Server — production;
  • Nginx — веб-сервер/reverse proxy;
  • Node.js — приложение;
  • npm — менеджер пакетов;
  • PM2 — управление Node.js-процессом;
  • SSH — безопасное подключение к серверу;
  • CI/CD runner — выполнение pipeline.

Но сама концепция не зависит от конкретных технологий. Вместо Node.js можно использовать PHP, Python, Go или другой стек.


Шаг 1. Подготовить Git-репозиторий

Начнём с проекта.

Например:

my-project/
├── src/
├── public/
├── tests/
├── package.json
├── package-lock.json
└── README.md

Важный принцип: в Git должны находиться исходный код и конфигурация проекта, но не секреты production-среды.

В .gitignore обычно добавляют:

node_modules/
.env
.env.local
dist/
build/
coverage/

Если .env содержит пароли, токены или ключи, его нельзя коммитить.

Вместо этого в репозитории можно хранить пример:

.env.example

Например:

DATABASE_URL=
API_KEY=
PORT=3000

Шаг 2. Определить стратегию ветвления

До автоматизации деплоя необходимо определить, какие ветки соответствуют каким окружениям.

Простой вариант:

develop → staging
main    → production

Тогда:

feature/login
       ↓
Pull Request
       ↓
develop
       ↓
staging
       ↓
main
       ↓
production

Это безопаснее, чем автоматически отправлять каждый commit из любой ветки прямо в production.

Для небольшого проекта можно использовать ещё более простой процесс:

feature
   ↓
Pull Request
   ↓
main
   ↓
production

Главное — заранее зафиксировать правила.


Шаг 3. Подготовить сервер

Предположим, приложение будет размещено в:

/var/www/my-project

На сервере должен быть установлен необходимый стек.

Например:

sudo apt update
sudo apt install nginx git

Для Node.js дополнительно устанавливается Node.js соответствующей версии.

Создадим пользователя для деплоя:

sudo adduser deploy

При необходимости добавим его к нужным группам.

Например:

sudo usermod -aG www-data deploy

Конкретные права зависят от архитектуры проекта.

Не стоит выполнять весь pipeline от имени root.

Если pipeline получит полный доступ к серверу, компрометация CI/CD может привести к компрометации всей машины.


Шаг 4. Создать отдельную директорию приложения

Например:

sudo mkdir -p /var/www/my-project
sudo chown -R deploy:deploy /var/www/my-project

Теперь пользователь deploy сможет работать с проектом без необходимости использовать sudo для каждой команды.


Шаг 5. Настроить SSH-доступ для CI/CD

CI/CD runner должен каким-то образом получить доступ к production-серверу.

Обычно используется SSH-ключ.

Логика выглядит так:

CI runner
   │
   │ private key
   ▼
SSH
   │
   ▼
Production server

На сервере хранится публичный ключ:

~/.ssh/authorized_keys

А приватный ключ хранится в защищённых secrets CI/CD-системы.

Важно:

Приватный SSH-ключ нельзя помещать в Git-репозиторий.


Шаг 6. Настроить secrets

В CI/CD-системе создаются переменные:

DEPLOY_HOST
DEPLOY_USER
SSH_PRIVATE_KEY

Например:

DEPLOY_HOST=203.0.113.10
DEPLOY_USER=deploy

А SSH_PRIVATE_KEY содержит приватный ключ.

Дополнительно могут понадобиться:

DATABASE_URL
NODE_ENV
API_URL
SENTRY_AUTH_TOKEN
DOCKER_REGISTRY_TOKEN

Секреты должны храниться в механизме secrets выбранной CI/CD-платформы.


Шаг 7. Описать pipeline как код

Одна из главных особенностей современной CI/CD-системы — pipeline хранится вместе с проектом.

Например, для GitHub Actions используется:

.github/workflows/deploy.yml

Условный pipeline может выглядеть следующим образом:

name: Deploy

on:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

      - name: Build
        run: npm run build

  deploy:
    needs: test
    runs-on: ubuntu-latest

    steps:
      - name: Deploy
        run: |
          echo "$SSH_PRIVATE_KEY" > key
          chmod 600 key

          ssh -i key \
            -o StrictHostKeyChecking=no \
            $DEPLOY_USER@$DEPLOY_HOST \
            "cd /var/www/my-project && ./deploy.sh"

Это только пример архитектуры. В production pipeline необходимо дополнительно продумать проверку SSH host key, работу с артефактами, откатами и секретами.


Почему тесты должны выполняться до deploy

Представим, что разработчик допустил ошибку:

function calculatePrice(product) {
    return product.price * quantity;
}

Переменная quantity не определена.

Если pipeline сразу выполняет:

git push
 ↓
deploy

ошибочный код окажется на production.

Правильнее:

git push
 ↓
lint
 ↓
tests
 ↓
build
 ↓
deploy

Если тесты завершаются ошибкой:

Tests failed
     ↓
Pipeline stopped
     ↓
Deploy не выполняется

Это один из главных принципов CI/CD: неуспешная проверка должна блокировать публикацию.


Шаг 8. Создать deploy-скрипт

Чтобы не помещать всю логику деплоя непосредственно в CI-конфигурацию, удобно вынести её в отдельный скрипт.

Например:

#!/usr/bin/env bash

set -e

cd /var/www/my-project

echo "Updating source..."

git fetch origin
git reset --hard origin/main

echo "Installing dependencies..."

npm ci --omit=dev

echo "Building application..."

npm run build

echo "Restarting application..."

pm2 reload my-project

echo "Deployment completed."

Сделаем файл исполняемым:

chmod +x deploy.sh

Теперь pipeline запускает:

./deploy.sh

Преимущество такого подхода в том, что deployment logic находится рядом с кодом проекта и её проще тестировать и изменять.


Но стоит ли делать git pull на production?

Это зависит от архитектуры.

Простой вариант:

git fetch origin
git reset --hard origin/main
npm ci
npm run build

подходит для небольших проектов.

Однако у него есть недостаток: production-сервер сам получает исходный код и самостоятельно собирает приложение.

Более зрелая архитектура:

Git
 ↓
CI
 ↓
Build
 ↓
Artifact / Docker image
 ↓
Production

В этом случае production получает уже готовый артефакт.

Например:

npm ci
npm run build

выполняется в CI, после чего результат передаётся серверу.

Для крупных проектов это обычно более предсказуемый подход.


Вариант с Docker

Если приложение работает в Docker, pipeline может выглядеть так:

Git push
    ↓
CI
    ↓
Tests
    ↓
Docker build
    ↓
Docker image
    ↓
Container Registry
    ↓
Production
    ↓
docker pull
    ↓
docker compose up -d

Например, pipeline может собрать образ:

docker build -t my-project:$GIT_SHA .

После этого образ отправляется в registry:

docker push registry.example.com/my-project:$GIT_SHA

На сервере:

docker pull registry.example.com/my-project:$GIT_SHA

И запускается новая версия контейнера.

Преимущество подхода — одинаковая среда сборки и выполнения приложения.


Что делать с базой данных

Миграции базы данных — один из наиболее важных вопросов при автоматическом деплое.

Например, проект использует Prisma, Laravel migrations, Django migrations или другой механизм.

В pipeline может появиться отдельный шаг:

npm run migrate

Но запуск миграций требует осторожности.

Нужно учитывать:

  • обратную совместимость схемы;
  • блокировки таблиц;
  • размер базы;
  • возможность отката;
  • время выполнения миграции;
  • совместимость старой и новой версии приложения.

Не каждая миграция безопасна для автоматического запуска в production.

Хорошая практика — проектировать изменения базы данных по принципу backward compatibility.

Например, вместо:

Удалить старую колонку
↓
Развернуть новую версию

лучше:

1. Добавить новую колонку
2. Развернуть код, использующий обе колонки
3. Перенести данные
4. Убедиться, что старая колонка больше не используется
5. Удалить старую колонку отдельным изменением

Шаг 9. Добавить health check

Успешное выполнение команды deploy ещё не означает, что приложение действительно работает.

Например:

npm run build → OK
pm2 reload → OK

Но приложение может отвечать:

HTTP 500

Поэтому после деплоя желательно выполнить проверку.

Например:

curl --fail https://example.com/health

Если сервер отвечает ошибкой:

curl → 500
      ↓
pipeline failed

Если:

curl → 200
      ↓
deployment successful

Для этого удобно иметь endpoint:

GET /health

который возвращает:

{
  "status": "ok"
}

Для сложных систем health check может проверять также доступность критически важных зависимостей.


Шаг 10. Добавить автоматический rollback

Одна из самых полезных функций production CI/CD — возможность быстро вернуться к предыдущей версии.

Допустим:

v104 → deploy
       ↓
       ошибка

Вместо ручного исправления можно выполнить:

rollback
   ↓
v103

Для этого версии должны быть идентифицируемыми.

Например:

release-a81f23
release-c71a90
release-d92b10

Или использовать SHA коммита:

a81f23c
c71a90e
d92b10f

Чем проще определить и развернуть предыдущий артефакт, тем надёжнее система.


Blue-Green и Canary Deployment

Для критичных проектов можно пойти дальше обычного deploy → restart.

Blue-Green

Создаются две версии:

Blue  → текущая версия
Green → новая версия

Новая версия разворачивается в Green:

Users
  ↓
Blue

Green ← новая версия

После проверки трафик переключается:

Users
  ↓
Green

Если что-то пошло не так, можно вернуть трафик на Blue.

Canary

Новая версия сначала получает только часть трафика:

95% → old version
5%  → new version

Если ошибок нет:

80% → old
20% → new

И постепенно:

0% → old
100% → new

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


Как организовать staging

Перед production полезно иметь staging-среду.

Например:

develop
   ↓
CI
   ↓
Deploy staging
   ↓
QA / review
   ↓
main
   ↓
CI
   ↓
Deploy production

Staging должен быть максимально похож на production.

Это позволяет обнаружить проблемы до публикации.

Например:

  • неправильную переменную окружения;
  • ошибку миграции;
  • проблему сборки;
  • несовместимость версии Node.js;
  • ошибку конфигурации Nginx;
  • проблему с внешним API.

Что логировать

При каждом deploy желательно сохранять информацию:

Commit: a81f23c
Branch: main
Author: developer
Started: 10:31
Build: success
Tests: 154 passed
Deploy: success
Health check: 200

В случае ошибки:

Build: success
Tests: success
Deploy: failed
Reason: SSH connection timeout

Такие данные значительно ускоряют диагностику.


Безопасность CI/CD

Автоматизация не должна происходить за счёт снижения безопасности.

Не храните секреты в Git

Плохо:

password: super-secret-password

Хорошо:

password: ${{ secrets.DATABASE_PASSWORD }}

Используйте отдельного deploy-пользователя

Не следует давать CI/CD полный root-доступ без необходимости.

Ограничивайте SSH-ключ

Если инфраструктура позволяет, используйте отдельный ключ исключительно для deployment.

Проверяйте зависимости

Pipeline должен обнаруживать уязвимости в используемых пакетах.

Например:

npm audit

Но автоматическое падение pipeline на любой найденной уязвимости нужно настраивать осознанно: иначе критичные и некритичные проблемы будут смешиваться.

Защищайте production-ветку

Полезно требовать:

  • Pull Request;
  • code review;
  • успешные CI checks;
  • запрет прямого push в main.

Как избежать простоя во время деплоя

Простейший вариант:

pm2 restart app

может привести к короткому перерыву.

Для некоторых приложений этого достаточно.

Для сервисов с высокими требованиями к доступности применяются:

  • graceful reload;
  • несколько экземпляров приложения;
  • reverse proxy;
  • load balancer;
  • rolling deployment;
  • blue-green deployment.

Например:

Nginx
  │
  ├── App instance 1
  ├── App instance 2
  └── App instance 3

Можно обновлять экземпляры постепенно, сохраняя доступность сервиса.


Типичные ошибки при создании CI/CD

Ошибка №1. Деплой каждого push в production

Такой подход может привести к публикации незавершённой функциональности.

Лучше:

feature
 ↓
PR
 ↓
CI
 ↓
review
 ↓
main
 ↓
production

Ошибка №2. Хранение паролей в репозитории

Если секрет попал в Git, недостаточно просто удалить его из последнего commit. Он мог остаться в истории.

Секрет необходимо отозвать и заменить.

Ошибка №3. Использование root

Если CI runner скомпрометирован, злоумышленник может получить полный контроль над сервером.

Используйте минимально необходимые права.

Ошибка №4. Отсутствие health check

Pipeline сообщает:

Deployment successful

хотя приложение фактически возвращает HTTP 500.

После деплоя необходима проверка реального состояния сервиса.

Ошибка №5. Отсутствие rollback

Любой production deploy потенциально может завершиться неудачей.

Поэтому ещё до первого автоматического деплоя стоит ответить на вопрос:

Как мы вернём предыдущую рабочую версию?

Ошибка №6. Сборка непосредственно на production

Для небольших проектов это допустимо, но по мере роста системы лучше собирать артефакты в CI и доставлять именно проверенный результат.


Минимальный production-ready pipeline

Для типичного веб-проекта можно начать с такой схемы:

Developer
    │
    │ Pull Request
    ▼
Git Repository
    │
    ▼
CI
 ┌───────────────┐
 │ Install       │
 │ Lint          │
 │ Unit tests    │
 │ Build         │
 └───────┬───────┘
         │
       success
         │
         ▼
      Deploy
         │
         ▼
    Health check
         │
    ┌────┴────┐
    │         │
   OK       Error
    │         │
    ▼         ▼
Success    Rollback

Это уже значительно надёжнее ручного копирования файлов на сервер.


Как масштабировать систему

Когда проектов становится больше, можно перейти от простого deployment script к полноценной инфраструктуре.

Например:

Git
 ↓
CI
 ↓
Tests
 ↓
Build
 ↓
Artifact Registry
 ↓
Infrastructure
 ↓
Staging
 ↓
Approval
 ↓
Production
 ↓
Monitoring

Дополнительно можно использовать:

  • Docker;
  • Kubernetes;
  • Terraform;
  • Ansible;
  • managed cloud services;
  • централизованный мониторинг;
  • системы логирования;
  • error tracking.

При этом не стоит усложнять инфраструктуру только ради современных инструментов.

Если проект представляет собой небольшой корпоративный сайт, схема:

Git → CI → SSH → VPS → Nginx

может быть полностью достаточной.


Практический чек-лист CI/CD для веб-проекта

Перед запуском автоматического production deploy проверьте:

  • Код хранится в Git.
  • Production-ветка защищена.
  • Pipeline запускается автоматически.
  • Установлены зависимости.
  • Выполняется линтинг.
  • Запускаются автоматические тесты.
  • Выполняется production build.
  • Secrets не находятся в репозитории.
  • Для деплоя используется отдельный пользователь.
  • SSH-доступ ограничен.
  • Production-сервер не требует ручного ввода пароля.
  • После деплоя выполняется health check.
  • Есть способ быстро определить текущую версию.
  • Есть процедура rollback.
  • Логи pipeline доступны команде.
  • Staging используется там, где он действительно нужен.
  • Миграции базы данных продуманы отдельно.
  • Есть мониторинг ошибок production.

Итог

CI/CD — это не просто команда, которая выполняет git pull после каждого push. Хорошая система автоматического деплоя создаёт контролируемую цепочку:

Изменение кода
      ↓
Git
      ↓
Автоматические проверки
      ↓
Тестирование
      ↓
Сборка
      ↓
Деплой
      ↓
Health check
      ↓
Мониторинг

Для небольшого веб-проекта вполне достаточно начать с Git, CI/CD runner, SSH и отдельного deploy-скрипта. По мере роста проекта можно перейти к сборке артефактов, Docker, staging, автоматическим миграциям, blue-green deployment и полноценному rollback.

Главный принцип при этом остаётся неизменным: деплой должен быть воспроизводимым, безопасным и максимально независимым от ручных действий человека.

Именно поэтому CI/CD особенно полезен веб-студиям: однажды стандартизировав процесс, команда получает единый подход к публикации новых версий, сокращает количество технических ошибок и освобождает разработчиков от рутинных операций.


Читайте также:

Приглашаем поучаствовать в обсуждении статьи:

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