Представим, что вы разрабатываете SaaS-платформу для управления проектами. Frontend написан на React, Backend — на Python с FastAPI, PostgreSQL используется для хранения данных, а Redis — для кеширования и фоновых задач. Приложение работает на VPS под управлением Linux. Для запуска сервисов используется Docker Compose, а Nginx принимает внешние HTTP-запросы. На первых этапах разработчик обновляет приложение вручную.
Он подключается к серверу по SSH, загружает изменения из GitHub, пересобирает Docker-контейнеры и перезапускает сервисы. Пока проект небольшой, такой подход кажется удобным. Но постепенно появляются проблемы. Однажды разработчик забывает выполнить миграцию PostgreSQL. В другой раз на сервер попадает код, который не проходил тестирование.
После очередного обновления Frontend перестаёт обращаться к Backend из-за неправильной переменной окружения. А когда новая версия приложения начинает возвращать ошибки, выясняется, что никто не подготовил механизм отката. Такие ситуации показывают, почему ручное развёртывание плохо масштабируется вместе с командой и продуктом.
CI/CD для Full Stack проектов позволяет автоматизировать проверку, сборку и доставку изменений. С помощью GitHub Actions можно запускать тесты после каждого Pull Request, собирать Docker-образы, публиковать их в Container Registry и развёртывать проверенные версии приложения.
Разберём, как настроить CI/CD через GitHub Actions, какие этапы должен содержать Pipeline и как организовать безопасный деплой React и FastAPI в Production.
Что такое CI/CD простыми словами
CI/CD — набор практик автоматизации разработки и доставки программного обеспечения. CI означает Continuous Integration — непрерывную интеграцию. CD может означать Continuous Delivery или Continuous Deployment. Эти понятия связаны, но отличаются. Что такое CI/CD простыми словами?
Это подход, при котором изменения кода автоматически проверяются, собираются и подготавливаются к развёртыванию, а в некоторых случаях — автоматически публикуются в Production. Основная цель — сделать выпуск новых версий более предсказуемым. Вместо последовательности ручных действий команда получает воспроизводимый процесс.
1. Что такое Continuous Integration
Continuous Integration — практика частого объединения изменений разработчиков с основной веткой проекта. После каждого изменения запускаются автоматические проверки. Например:
- проверка форматирования;
- статический анализ;
- Unit Tests;
- Integration Tests;
- сборка Frontend;
- проверка Backend.
Continuous Integration для веб-приложений помогает обнаруживать проблемы до попадания изменений в Production. Представим, что разработчик изменил модель пользователя в FastAPI. После открытия Pull Request GitHub Actions запускает тесты. Если изменение нарушило работу авторизации, Pipeline завершается ошибкой. Команда узнаёт о проблеме до объединения кода.
2. Continuous Delivery и Continuous Deployment
Эти понятия часто используют как синонимы, но между ними есть различие. Continuous Delivery означает, что приложение постоянно находится в состоянии готовности к выпуску. Проверенная версия может быть развёрнута после ручного подтверждения. Continuous Deployment предполагает, что изменения, прошедшие необходимые проверки, автоматически отправляются в Production без обязательного ручного шага. Например: Developer Push
| v Automated Tests | v Docker Build | v Security Checks | v Production Deployment Разница между Continuous Delivery и Continuous Deployment заключается в наличии или отсутствии обязательного ручного решения о выпуске. Для критичных систем может быть полезен ручной этап подтверждения. Для небольших SaaS-приложений автоматический деплой после успешных проверок часто ускоряет разработку.
3. Почему Full Stack проекту нужен CI/CD
Full Stack приложение обычно состоит из нескольких компонентов. Например: React Frontend | v FastAPI Backend | +-- PostgreSQL | +-- Redis | +-- Background Workers Изменение одного компонента может влиять на другие. Например, Backend изменяет структуру JSON-ответа, а React продолжает ожидать старый формат. Или новая версия Backend требует миграции базы данных.
Автоматизация разработки и деплоя Full Stack помогает согласованно проверять разные части приложения. Хорошо настроенный Pipeline может обнаруживать проблемы на нескольких уровнях:
- синтаксис и форматирование;
- ошибки типов;
- нарушения бизнес-логики;
- несовместимость API;
- ошибки сборки;
- проблемы конфигурации;
- ошибки развёртывания.
Но CI/CD не гарантирует отсутствие ошибок. Качество результата зависит от проверок, которые команда включила в Pipeline.
4. Что такое GitHub Actions
GitHub Actions — система автоматизации рабочих процессов, интегрированная с GitHub. Она позволяет запускать задачи в ответ на события репозитория. Например:
- push;
- pull_request;
- создание релиза;
- ручной запуск;
- выполнение по расписанию.
GitHub Actions для Full Stack разработчика позволяет хранить конфигурацию автоматизации рядом с кодом проекта. Рабочие процессы описываются YAML-файлами. Обычно они находятся в директории: .github/workflows/ Например: .github/ └── workflows/ ├── ci.yml └── deploy.yml
5. Как работает GitHub Actions Workflow
Workflow — автоматизированный процесс, состоящий из заданий. Задание называется Job. Внутри Job выполняются отдельные шаги — Steps. GitHub Actions Workflow YAML описывает события запуска, окружение и последовательность команд. Простейший пример: name: Hello CI on: push: branches: [main] jobs: hello: runs-on: ubuntu-latest steps: - name: Print message run: echo "CI pipeline started"
Когда разработчик отправляет изменения в ветку main, GitHub запускает Workflow. Job выполняется на Runner — машине, предоставляющей среду выполнения.
Что такое GitHub Actions Runner
Runner — система, на которой выполняются задания GitHub Actions. GitHub предоставляет собственные Hosted Runners. Также можно использовать Self-Hosted Runners. GitHub Actions Runner выполняет команды, устанавливает зависимости, запускает тесты и собирает приложения. Для большинства небольших проектов Hosted Runner — удобный старт. Self-Hosted Runner может быть полезен при специальных требованиях к инфраструктуре.
Однако его необходимо самостоятельно обновлять, защищать и обслуживать. Особенно осторожно следует относиться к запуску непроверенного кода на Runner, имеющем доступ к Production.
6. Как организовать репозиторий Full Stack проекта
Представим Monorepo с React и FastAPI. fullstack-app/ ├── frontend/ │ ├── src/ │ ├── package.json │ ├── package-lock.json │ └── Dockerfile ├── backend/ │ ├── app/ │ ├── tests/ │ ├── pyproject.toml │ ├── uv.lock │ ├── alembic/ │ └── Dockerfile ├── deploy/ │ ├── compose.prod.yml │ └── nginx.conf ├── .github/ │ └── workflows/ │ ├── ci.yml │ └── deploy.yml └── README.md
CI/CD для Monorepo React и FastAPI позволяет запускать отдельные проверки Frontend и Backend. Например, изменение React-компонента не обязательно должно запускать все тяжёлые интеграционные тесты Backend. Однако оптимизация Pipeline должна сохранять проверки совместимости там, где компоненты зависят друг от друга.
7. Как настроить CI для React
Начнём с Frontend. Предположим, что React-приложение создано через Vite. В package.json определены команды: { "scripts": { "dev": "vite", "build": "vite build", "lint": "eslint .", "test": "vitest run" } } CI для React приложения должен как минимум проверять корректность зависимостей и возможность сборки. Если проект использует TypeScript, полезно отдельно запускать проверку типов.
Пример GitHub Actions для React
Создадим файл .github/workflows/ci.yml. name: Full Stack CI on: pull_request: push: branches: [main] permissions: contents: read jobs: frontend: name: React Checks runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "22" cache: npm
cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci - name: Run ESLint run: npm run lint - name: Run tests run: npm test - name: Build React run: npm run build GitHub Actions React Vite пример запускает установку зависимостей, линтер, тесты и Production-сборку. Команда npm ci использует зафиксированные версии зависимостей из lock-файла.
Это помогает получать более воспроизводимые результаты. Для особенно строгих требований к безопасности можно фиксировать используемые GitHub Actions по полным SHA-коммитам, а не только по тегам версий.
8. Как настроить автоматические тесты React
Для тестирования React можно использовать Vitest и React Testing Library. Например, проверим компонент кнопки. export default function SaveButton({ onSave }) { return ( <button onClick={onSave}> Save </button> ); } Тест:
import { render, screen, fireEvent } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import SaveButton from "./SaveButton";
describe("SaveButton", () => { it("calls onSave when clicked", () => { const onSave = vi.fn(); render(<SaveButton onSave={onSave} />); fireEvent.click( screen.getByRole("button", { name: "Save" }) ); expect(onSave).toHaveBeenCalledOnce(); }); }); Для работы такого теста необходимо настроить подходящее DOM-окружение Vitest, например jsdom.
Автоматическое тестирование React через Vitest помогает проверять поведение компонентов до объединения изменений. Но Unit Tests не заменяют End-to-End тестирование пользовательских сценариев.
9. Как настроить CI для FastAPI
Теперь перейдём к Backend. Предположим, что FastAPI использует Python 3.12, pytest и Ruff. В проекте можно определить зависимости через pyproject.toml. CI для Python FastAPI должен проверять качество кода, бизнес-логику и работу API. Например, полезно запускать:
- Ruff;
- pytest;
- проверку миграций;
- Integration Tests с PostgreSQL.
Пример GitHub Actions для FastAPI
Добавим второе задание в тот же ci.yml. backend: name: FastAPI Checks runs-on: ubuntu-latest defaults: run: working-directory: backend steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install uv uses: astral-sh/setup-uv@v5 - name: Install dependencies run: uv sync --frozen --extra dev - name: Run Ruff
run: uv run ruff check . - name: Run tests run: uv run pytest -q Этот пример предполагает, что в pyproject.toml настроена дополнительная группа зависимостей dev как optional extra, а uv.lock уже существует. Если проект использует dependency groups, команда установки должна соответствовать выбранной конфигурации. GitHub Actions FastAPI pytest пример показывает базовую автоматизацию проверки Backend.
В реальном проекте тесты должны учитывать конфигурацию базы данных и внешних сервисов.
10. Как тестировать FastAPI с PostgreSQL
Многие ошибки невозможно обнаружить без настоящей базы данных. Например:
- некорректные SQL-запросы;
- ошибки миграций;
- проблемы уникальных ограничений;
- несовместимость типов;
- неправильное поведение транзакций.
Поэтому в CI полезно запускать PostgreSQL как Service Container. PostgreSQL в GitHub Actions позволяет тестировать Backend в окружении, приближенном к Production.
Пример PostgreSQL Service Container
backend-integration: name: Backend Integration Tests runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_USER: test_user POSTGRES_PASSWORD: test_password POSTGRES_DB: test_db ports: - 5432:5432 options: >- --health-cmd "pg_isready -U test_user -d test_db" --health-interval 10s --health-timeout 5s --health-retries 5 env:
DATABASE_URL: postgresql+asyncpg://test_user:test_password@localhost:5432/test_db steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - uses: astral-sh/setup-uv@v5 - name: Install dependencies working-directory: backend run: uv sync --frozen --extra dev - name: Apply migrations working-directory: backend run: uv run alembic upgrade head - name: Run integration tests
working-directory: backend run: uv run pytest tests/integration -q Integration Tests FastAPI PostgreSQL помогают проверить работу Backend с реальной СУБД. Пароль в примере используется только для изолированного тестового контейнера. Его нельзя переносить в Production-конфигурацию.
11. Как использовать Redis в CI
Если Backend использует Redis для кеширования или фоновых задач, его тоже можно добавить как Service Container. services: redis: image: redis:7 ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 Redis Service Container GitHub Actions позволяет тестировать операции кеширования и интеграции с Redis.
Но наличие Redis в CI не означает, что все фоновые задачи автоматически выполняются. Для тестирования очередей могут потребоваться отдельные Worker-процессы.
12. Как настроить проверки Pull Request
Одна из главных целей CI — не допускать непроверенные изменения в основную ветку. Для этого GitHub поддерживает правила защиты веток. Например, можно потребовать:
- успешное выполнение Frontend Checks;
- успешное выполнение Backend Checks;
- Code Review;
- отсутствие конфликтов;
- актуальность ветки относительно main.
Branch Protection Rules GitHub помогают сделать проверки обязательной частью разработки. Однако наличие Workflow само по себе не запрещает объединять Pull Request с ошибками. Необходимо отдельно настроить соответствующие правила репозитория.
13. Как ускорить GitHub Actions Pipeline
Со временем количество тестов увеличивается. Pipeline может выполняться десять, двадцать или тридцать минут. Это замедляет обратную связь. Оптимизация GitHub Actions Pipeline помогает уменьшить время ожидания разработчиков. Полезные подходы:
- кеширование зависимостей;
- параллельные Jobs;
- разделение быстрых и тяжёлых тестов;
- запуск проверок по изменённым путям;
- переиспользование Docker-слоёв;
- устранение дублирующихся операций.
Но ускорение не должно приводить к пропуску критически важных проверок.
Как использовать параллельные Jobs
В GitHub Actions независимые Jobs могут выполняться параллельно. Например: Pull Request | +-----------+-----------+ | | v v React Tests FastAPI Tests | | +-----------+-----------+ | v Build Check Параллельные Jobs GitHub Actions позволяют одновременно проверять Frontend и Backend. Для последовательного выполнения можно использовать needs. Например, Job сборки может зависеть от успешного завершения тестов.
14. Как настроить Docker для Production
В Full Stack проекте удобно собирать отдельные Docker-образы Frontend и Backend. Для Backend можно использовать следующий Dockerfile. FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app ./app COPY alembic ./alembic COPY alembic.ini . EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Это упрощённый пример, предполагающий, что requirements.txt содержит все необходимые зависимости. Dockerfile для FastAPI Production должен учитывать безопасность, размер образа и воспроизводимость зависимостей. В реальном проекте полезно запускать приложение от непривилегированного пользователя, фиксировать зависимости и исключать лишние файлы. Также не следует включать секреты в Docker-образ.
15. Как собрать React в Docker
Для React-приложения можно использовать многоэтапную сборку. На первом этапе Node.js собирает статические файлы. На втором Nginx обслуживает готовую сборку. FROM node:22-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html EXPOSE 80
Multi-Stage Docker Build для React позволяет не включать Node.js и исходные зависимости разработки в итоговый образ. Для SPA с клиентской маршрутизацией может потребоваться дополнительная настройка Nginx, чтобы неизвестные маршруты возвращали index.html.
16. Как собирать Docker-образы через GitHub Actions
После успешных тестов Pipeline может собрать Docker-образы. Для этого используется Docker Buildx. Docker Build GitHub Actions позволяет автоматизировать сборку контейнеров. Например: name: Docker Build on: push: branches: [main] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - name: Build Backend Image
uses: docker/build-push-action@v6 with: context: ./backend push: false tags: fullstack-backend:test Параметр push: false означает, что образ собирается для проверки, но не публикуется в Registry.
17. Что такое Docker Container Registry
Container Registry — хранилище Docker-образов. Например:
- GitHub Container Registry;
- Docker Hub;
- Amazon ECR;
- Google Artifact Registry.
GitHub Container Registry GHCR позволяет хранить образы рядом с GitHub-проектом. Обычно адрес образа выглядит так: ghcr.io/organization/project-backend:version Для Production важно использовать конкретные версии образов. Не стоит полагаться только на тег latest. Он может указывать на разные сборки в разные моменты времени.
18. Как публиковать Docker-образ в GHCR
Для публикации образа GitHub Actions может использовать встроенный GITHUB_TOKEN. name: Publish Backend on: push: branches: [main] permissions: contents: read packages: write jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: {{ github.sha }}
Здесь example необходимо заменить на реального владельца Registry. Публикация Docker образов через GitHub Actions позволяет автоматически создавать артефакты для последующего развёртывания. Тег с SHA-коммитом помогает связать образ с конкретной версией исходного кода. Но для наиболее строгой воспроизводимости при развёртывании лучше использовать digest образа.
19. Почему нельзя хранить секреты в GitHub
Представим, что приложение использует: DATABASE_URL REDIS_URL JWT_SECRET STRIPE_SECRET_KEY SSH_PRIVATE_KEY Если такие значения попадут в Git-репозиторий, они могут быть раскрыты. GitHub Actions Secrets позволяют хранить чувствительные значения отдельно от исходного кода. Например, секреты можно добавить через настройки репозитория или Environment.
После этого они становятся доступны Workflow при соблюдении соответствующих правил доступа.
Как использовать Secrets в Workflow
steps: - name: Use deployment secret env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} run: | echo "Deployment target configured" В этом примере секрет передаётся через переменную окружения, но его значение не выводится в лог. Безопасное хранение секретов GitHub Actions требует минимизации доступа. Не следует выводить секреты через echo, включать их в Docker-образы или передавать в недоверенные скрипты.
Также важно помнить, что маскирование секретов в логах не является абсолютной защитой от всех способов утечки.
20. Что такое GitHub Environments
GitHub Environments позволяют разделять настройки разных окружений. Например: development staging production Для Production можно установить дополнительные ограничения. Например, разрешить деплой только из определённой ветки или потребовать подтверждение уполномоченного пользователя, если соответствующие возможности доступны для репозитория и тарифа.
GitHub Environments для Production помогают контролировать доступ к развёртыванию. Это особенно полезно, когда над проектом работает несколько разработчиков.
21. Как организовать Staging и Production
Staging — окружение для проверки приложения перед выпуском. Оно должно быть достаточно похоже на Production, чтобы выявлять конфигурационные и интеграционные ошибки. Staging Environment для Full Stack проекта может использовать:
- отдельный Backend;
- отдельную базу данных;
- отдельный Redis;
- тестовые внешние интеграции;
- собственные секреты.
Например: Pull Request | v CI Tests | v Merge to Main | v Deploy to Staging | v Smoke Tests | v Production Approval | v Deploy to Production Не стоит использовать Production-базу данных для обычных тестов Staging.
22. Как настроить деплой через SSH
Один из простых способов автоматизировать развёртывание на VPS — подключаться к серверу по SSH. После подключения Pipeline выполняет необходимые команды. Деплой через GitHub Actions на VPS может использовать отдельного пользователя с ограниченными правами. На сервере заранее должны быть установлены Docker и Docker Compose. Также необходимо настроить доступ к Container Registry.
Пример SSH Deployment
Упрощённый Workflow: name: Deploy Production on: workflow_dispatch: permissions: contents: read jobs: deploy: runs-on: ubuntu-latest environment: production steps: - name: Configure SSH env: SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} SSH_HOST: ${{ secrets.DEPLOY_HOST }} run: | mkdir -p ~/.ssh chmod 700 ~/.ssh printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "$SSH_HOST" >> ~/.ssh/known_hosts - name: Deploy application env: SSH_HOST: ${{ secrets.DEPLOY_HOST }} SSH_USER: ${{ secrets.DEPLOY_USER }} run: | ssh -i ~/.ssh/deploy_key \ "SSH_HOST" \ "cd /opt/fullstack-app && ./deploy.sh" Этот пример демонстрирует общий механизм, но не является полностью защищённой Production-конфигурацией.
В частности, ssh-keyscan без независимой проверки отпечатка сервера не защищает от подмены SSH-хоста. Для Production следует заранее получить и проверить SSH host key, а затем сохранить доверенное значение в настройках развёртывания. SSH Deployment GitHub Actions должен использовать отдельный ключ с минимально необходимыми правами.
Не следует предоставлять Runner полный административный доступ к серверу без необходимости.
23. Как использовать Docker Compose в Production
Предположим, что на сервере находится файл compose.prod.yml. services: backend: image: ghcr.io/example/fullstack-backend:{APP_VERSION} restart: unless-stopped ports: - "127.0.0.1:8080:80" networks: - app_network networks: app_network: Здесь APP_VERSION — идентификатор версии, который задаётся во время деплоя. PostgreSQL и Redis могут запускаться отдельно или через другие сервисы Docker Compose.
Docker Compose Production Deployment позволяет обновлять контейнеры из заранее собранных образов. Важно, чтобы Production-сервер не пересобирал приложение из случайного состояния исходного кода. Лучше развёртывать конкретный проверенный артефакт.
24. Как написать deploy.sh
На сервере можно создать скрипт: #!/usr/bin/env bash set -euo pipefail cd /opt/fullstack-app docker compose -f compose.prod.yml pull docker compose -f compose.prod.yml up -d docker compose -f compose.prod.yml ps Автоматический деплой Docker Compose позволяет заменить несколько ручных команд одним воспроизводимым процессом.
Но этот скрипт не выполняет полноценную проверку здоровья приложения и не обеспечивает автоматический откат. Для Production необходимо добавить соответствующие проверки. Также значение APP_VERSION должно быть задано заранее.
25. Как использовать Health Check
После развёртывания контейнер может находиться в состоянии Running, но приложение при этом не обязательно готово обрабатывать запросы. Например, FastAPI запустился, но не может подключиться к PostgreSQL. Health Check FastAPI Production помогает определить состояние приложения. Создадим endpoint: from fastapi import FastAPI app = FastAPI() @app.get("/health/live") async def liveness(): return {"status": "alive"}
Этот endpoint показывает, что процесс приложения отвечает на HTTP-запросы. Для проверки готовности можно создать отдельный /health/ready. Он может проверять критически важные зависимости, необходимые для обслуживания запросов. Однако не стоит превращать каждый Health Check в тяжёлую операцию.
26. Как проверить приложение после деплоя
После обновления необходимо выполнить Smoke Tests. Например: curl --fail \ --silent \ --show-error \
https://example.com/health/ready
Если endpoint возвращает ошибку, Pipeline должен сообщить о неуспешном развёртывании. Smoke Tests после деплоя помогают обнаруживать очевидные проблемы сразу после выпуска. Но одна успешная проверка /health/ready не гарантирует корректность всех пользовательских сценариев. Поэтому полезно дополнительно проверять авторизацию, критичные API и основные страницы приложения.
27. Как выполнять миграции PostgreSQL в CI/CD
Изменения Backend часто требуют изменения структуры базы данных. Например, необходимо добавить поле archived_at в таблицу проектов. Для FastAPI с SQLAlchemy можно использовать Alembic. Миграции PostgreSQL через Alembic в CI/CD позволяют управлять изменениями схемы базы данных. Например: alembic upgrade head Но запуск миграций требует особой осторожности.
Если новая версия приложения несовместима со старой схемой, а деплой проходит поэтапно, могут возникнуть ошибки.
28. Что такое Expand and Contract Migration
Expand and Contract — подход к безопасному изменению схемы базы данных. Представим, что необходимо переименовать поле username в display_name. Небезопасный вариант — удалить старое поле и сразу заменить его новым. Старая версия Backend может перестать работать. Expand and Contract Migration PostgreSQL предполагает постепенное изменение схемы. Например:
- Добавить новое поле.
- Обновить приложение для поддержки обоих полей.
- Перенести существующие данные.
- Переключить чтение на новое поле.
- Удалить старое поле в отдельном релизе.
Такой подход помогает поддерживать совместимость во время развёртывания и отката.
29. Как откатить неудачный деплой
Представим, что новая версия Backend вызывает ошибки. Необходимо быстро вернуться к предыдущей стабильной версии. Rollback Deployment GitHub Actions можно организовать через повторное развёртывание предыдущего Docker-образа. Например, если предыдущая версия имела тег: ghcr.io/example/fullstack-backend:abc123 Можно установить: export APP_VERSION=abc123 И выполнить: docker compose -f compose.prod.yml up -d
Но такой откат безопасен только при совместимости приложения со схемой базы данных и остальными компонентами. Откат Docker-образа не отменяет автоматически миграции PostgreSQL.
Почему миграции усложняют Rollback
Представим, что новая версия удалила столбец базы данных. После отката старый Backend ожидает этот столбец. В результате приложение не запускается. Поэтому безопасный откат релиза в Production требует проектирования обратной совместимости. Особенно важно разделять:
- откат кода;
- откат конфигурации;
- откат базы данных;
- восстановление данных из резервной копии.
Это разные операции. Для критичных изменений необходимо заранее подготовить план восстановления.
30. Что такое Blue-Green Deployment
Blue-Green Deployment — стратегия, при которой существуют две среды приложения. Blue — текущая Production-версия. Green — новая версия. Сначала новая версия разворачивается отдельно. После проверки трафик переключается на неё. Blue-Green Deployment для веб-приложения позволяет уменьшить риск простоя при обновлении. Схема: Load Balancer | +-------+-------+ | | v v Blue App Green App Version A Version B
После успешного переключения старая версия может временно оставаться доступной для отката. Но необходимо учитывать общую базу данных и совместимость схемы.
31. Что такое Rolling Deployment
Rolling Deployment — стратегия постепенного обновления экземпляров приложения. Например, если работает четыре Backend-инстанса, они могут обновляться по одному. Rolling Deployment Docker и Kubernetes позволяет уменьшать влияние обновления на доступность системы. Но обычный docker compose up -d на одном сервере не предоставляет автоматически полноценную стратегию Rolling Deployment.
Для неё необходимы соответствующие механизмы оркестрации или собственная инфраструктура управления трафиком.
32. Что такое Canary Deployment
Canary Deployment — стратегия, при которой новая версия сначала получает небольшую часть пользовательского трафика. Например:
95% → Version A
5% → Version B
Если показатели новой версии нормальные, долю трафика постепенно увеличивают. Canary Deployment для Full Stack приложения помогает обнаруживать проблемы до полного выпуска. Но для реализации требуется инфраструктура маршрутизации и мониторинга. Для небольшого VPS-проекта Canary Deployment может оказаться избыточным.
33. Как защитить CI/CD Pipeline
CI/CD имеет доступ к исходному коду, Docker Registry и иногда Production-инфраструктуре. Поэтому Pipeline становится важной частью системы безопасности. Безопасность CI/CD GitHub Actions требует учитывать:
- права GITHUB_TOKEN;
- доступ к Secrets;
- доверенность сторонних Actions;
- выполнение кода из Pull Request;
- защиту Production Environment;
- безопасность Docker-образов;
- защиту SSH-ключей;
- аудит изменений Workflow.
Особенно опасно предоставлять недоверенному коду доступ к секретам. Например, Workflow с событием pull_request_target требует повышенного внимания. Нельзя бездумно выполнять в таком контексте код из непроверенного Pull Request.
34. Как настроить минимальные Permissions
GitHub Actions позволяет явно задавать разрешения для GITHUB_TOKEN. Например: permissions: contents: read Для публикации пакетов можно добавить: permissions: contents: read packages: write Least Privilege GitHub Actions означает предоставление только необходимых прав. Это уменьшает потенциальный ущерб при компрометации Workflow или зависимости.
35. Как проверять Docker-образы на уязвимости
Docker-образы содержат системные библиотеки и зависимости приложения. Некоторые из них могут иметь известные уязвимости. Сканирование Docker образов в CI/CD помогает обнаруживать такие проблемы до Production. Для этого можно использовать специализированные инструменты, например Trivy. Пример локальной проверки: trivy image \ --severity HIGH,CRITICAL \ ghcr.io/example/fullstack-backend:abc123
Но наличие уязвимости в отчёте не всегда означает, что она эксплуатируема в конкретном приложении. Результаты необходимо анализировать с учётом контекста. Также сканирование не заменяет обновление зависимостей и безопасную разработку.
36. Как использовать Dependabot
Зависимости React, FastAPI и GitHub Actions необходимо регулярно обновлять. GitHub Dependabot может создавать Pull Request с обновлениями. Dependabot для GitHub Actions и Docker помогает поддерживать зависимости в актуальном состоянии. Пример конфигурации: version: 2 updates: - package-ecosystem: "npm" directory: "/frontend" schedule: interval: "weekly" - package-ecosystem: "pip" directory: "/backend" schedule:
interval: "weekly" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" - package-ecosystem: "docker" directory: "/backend" schedule: interval: "weekly" Поддержка конкретных файлов зависимостей зависит от выбранной экосистемы и структуры проекта. Обновления всё равно должны проходить автоматические тесты.
37. Как отслеживать ошибки после деплоя
Успешный Pipeline не означает, что приложение работает идеально. После выпуска необходимо отслеживать поведение Production. Полезные показатели:
- частота HTTP 5xx;
- время ответа API;
- количество ошибок JavaScript;
- использование CPU и памяти;
- ошибки подключения к PostgreSQL;
- длительность фоновых задач;
- количество неудачных запросов;
- показатели пользовательских сценариев.
Мониторинг после CI/CD деплоя помогает быстро обнаруживать регрессии. Например, после обновления Backend время ответа /api/projects увеличилось с 100 до 800 миллисекунд. Если команда отслеживает этот показатель, проблему можно обнаружить до большого количества жалоб пользователей.
38. Как организовать уведомления о деплое
После завершения Pipeline полезно сообщать команде результат. Например: Production Deployment Version: abc123 Status: Success Environment: production Уведомления GitHub Actions о деплое можно отправлять в Slack, Microsoft Teams или другие системы. Но уведомления должны быть полезными. Если команда получает десятки сообщений о каждом техническом шаге, важные ошибки могут потеряться.
Лучше выделять события, требующие внимания.
39. Как измерять эффективность CI/CD
CI/CD можно оценивать не только по факту наличия автоматизации. Полезно отслеживать:
- время выполнения Pipeline;
- частоту выпусков;
- процент неуспешных деплоев;
- время восстановления после ошибок;
- количество ручных операций;
- время от объединения Pull Request до Production.
Метрики CI/CD Pipeline помогают оценивать качество процесса доставки. Например, если Pipeline выполняется сорок минут, разработчики могут начать реже отправлять изменения. Если деплой занимает две минуты, но часто вызывает инциденты, проблема заключается не только в скорости. Важно учитывать надёжность выпуска.
40. Практическая архитектура CI/CD для React и FastAPI
Объединим рассмотренные подходы. Представим SaaS-проект со следующей инфраструктурой:
- React + Vite;
- FastAPI;
- PostgreSQL;
- Redis;
- Docker;
- GitHub Actions;
- GitHub Container Registry;
- VPS с Nginx.
Архитектура CI/CD React FastAPI Docker может выглядеть так: Developer | v GitHub Pull Request | +----------------------+ | | v v React CI FastAPI CI | | v v Lint + Tests Ruff + pytest | | v v Build PostgreSQL Tests | | +-----------+----------+ | v Merge to main | v Docker Build | v GitHub Container Registry | v Deploy Staging | v Smoke Tests | v Production Approval | v Deploy Production | v Health Check + Metrics
Эта схема разделяет проверку кода, создание артефактов и развёртывание. Такой подход помогает сделать процесс выпуска более управляемым.
41. Как избежать одновременных деплоев
Представим, что два разработчика почти одновременно объединяют Pull Request. Первый Pipeline начинает развёртывание версии A. Через минуту второй Pipeline начинает развёртывание версии B. Если оба процесса изменяют одни и те же контейнеры, возможны конфликты. Concurrency GitHub Actions Deployment позволяет ограничивать одновременное выполнение Workflow. Например: concurrency: group: production-deploy
cancel-in-progress: false Такой механизм помогает сериализовать развёртывания. Но важно учитывать, что ожидающие запуски могут заменяться более новыми в зависимости от поведения очереди GitHub Actions. Если требуется строго последовательная обработка каждого релиза, необходимо дополнительно продумать управление очередью.
42. Как организовать ручной запуск деплоя
Иногда необходимо развёртывать определённую версию вручную. Например, для отката или выпуска срочного исправления. GitHub Actions поддерживает workflow_dispatch. Ручной деплой через GitHub Actions можно реализовать с параметром версии. name: Manual Deployment on: workflow_dispatch: inputs: version: description: "Docker image version" required: true type: string jobs: deploy: runs-on: ubuntu-latest
environment: production steps: - name: Print selected version env: APP_VERSION: ${{ inputs.version }} run: | echo "Deploying version: $APP_VERSION" В полноценном Workflow выбранную версию необходимо проверить и передать в механизм развёртывания. Также важно убедиться, что пользователь не может указать произвольный непроверенный образ.
43. Почему важно разделять Build и Deploy
Одна из распространённых ошибок — собирать приложение непосредственно на Production-сервере. Например: git pull docker compose build docker compose up -d Этот подход зависит от состояния сервера и может создавать проблемы с воспроизводимостью. Разделение Build и Deploy в CI/CD предполагает, что приложение собирается заранее. Pipeline выполняет тесты, создаёт Docker-образ и публикует его в Registry.
Production получает уже готовый артефакт. Это помогает связывать конкретную версию приложения с конкретным набором проверок.
44. Как организовать деплой без простоя
Полностью избежать простоя сложнее, чем просто выполнить docker compose up -d. Для Zero Downtime Deployment Full Stack необходимо учитывать:
- количество экземпляров Backend;
- готовность новых контейнеров;
- балансировку нагрузки;
- завершение старых соединений;
- совместимость миграций;
- работу фоновых задач;
- долгоживущие WebSocket-соединения.
Например, если приложение использует WebSocket, при обновлении Backend существующие соединения могут разорваться. Frontend должен корректно переподключаться. Для критичных приложений стоит рассмотреть Blue-Green или Rolling Deployment.
45. Частые ошибки при настройке CI/CD
Первая ошибка — запускать тесты только локально. Вторая — объединять Pull Request без обязательных проверок. Третья — хранить секреты в репозитории. Четвёртая — использовать один и тот же пароль для тестовой и Production-базы данных. Пятая — развёртывать непроверенный Docker-образ. Шестая — использовать только тег latest без возможности определить точную версию. Седьмая — не выполнять Health Check после деплоя.
Восьмая — запускать несовместимые миграции PostgreSQL. Девятая — не иметь плана Rollback. Десятая — предоставлять Workflow избыточные разрешения. Одиннадцатая — использовать непроверенные сторонние Actions. Двенадцатая — выполнять недоверенный код с доступом к Production Secrets. Тринадцатая — не ограничивать одновременные деплои.
Четырнадцатая — считать успешную сборку доказательством готовности приложения к Production. Пятнадцатая — не отслеживать ошибки после выпуска. Эти ошибки CI/CD GitHub Actions могут приводить к нестабильным релизам, проблемам безопасности и длительному восстановлению после сбоев.
Чек-лист CI/CD перед запуском в Production
Перед внедрением автоматического развёртывания полезно проверить несколько направлений. Качество кода: запускаются ли линтеры, проверки типов и тесты? Frontend: выполняется ли Production-сборка React? Проверяются ли основные пользовательские сценарии? Backend: тестируется ли FastAPI с PostgreSQL? Проверяются ли миграции? Docker: собираются ли образы в CI? Можно ли определить точную версию каждого образа?
Secrets: хранятся ли чувствительные данные вне репозитория? Ограничены ли права Workflow? Deploy: используются ли проверенные артефакты? Есть ли защита от одновременных развёртываний? Database: совместимы ли миграции с текущей и предыдущей версиями приложения? Rollback: можно ли быстро вернуть предыдущую версию? Health Checks: проверяется ли готовность приложения после выпуска?
Monitoring: отслеживаются ли ошибки, задержки и состояние инфраструктуры? Security: проверяются ли зависимости и Docker-образы? Используются ли минимально необходимые разрешения? Такой чек-лист CI/CD для Production помогает уменьшить количество ошибок при выпуске новых версий.
FAQ
CI/CD — автоматизация проверки, сборки и доставки изменений программного обеспечения. GitHub Actions — встроенная в GitHub система автоматизации, позволяющая запускать Workflow в ответ на события репозитория. GitHub предоставляет определённые возможности и лимиты использования Actions, которые зависят от типа репозитория, Runner и условий тарифа. Актуальные ограничения следует проверять в документации GitHub.
Можно создать GitHub Actions Workflow, который устанавливает зависимости, запускает ESLint, тесты и Production-сборку. Можно использовать Python Runner, Ruff, pytest и PostgreSQL Service Container для автоматических проверок. Обычно Pipeline собирает образ, публикует его в Container Registry, а затем развёртывает конкретную версию на сервере.
Да. Один из вариантов — SSH-подключение с ограниченными правами и запуск заранее подготовленного скрипта развёртывания. Для этого можно использовать GitHub Actions Secrets и секреты соответствующих Environments. Можно использовать Alembic, но миграции необходимо проектировать с учётом обратной совместимости и возможности отката приложения.
Один из способов — повторно развернуть предыдущий проверенный Docker-образ. При этом необходимо учитывать совместимость базы данных. Это стратегия развёртывания с двумя окружениями, позволяющая переключать трафик между старой и новой версиями приложения. Это постепенный выпуск новой версии для небольшой части пользователей перед полным переключением трафика.
Нет. CI/CD можно настроить для VPS, Docker Compose и других вариантов инфраструктуры. Нужен баланс. Быстрые проверки ускоряют разработку, но не должны исключать тесты, необходимые для безопасного выпуска.
Заключение
CI/CD — один из важнейших инструментов современной Full Stack разработки. Он позволяет автоматизировать проверки, сборку и развёртывание приложения, уменьшая количество ручных операций. Для React и FastAPI можно настроить GitHub Actions, который запускает линтеры, Unit Tests, Integration Tests и Production-сборку. Docker позволяет создавать воспроизводимые образы приложения.
GitHub Container Registry помогает хранить проверенные версии. Docker Compose или другая инфраструктура развёртывания позволяет запускать эти версии на сервере. Но качественный CI/CD не ограничивается автоматическим выполнением команды docker compose up -d. Необходимо учитывать безопасность секретов, миграции PostgreSQL, Health Checks, мониторинг, управление версиями и возможность Rollback.
Особенно важно разделять сборку и развёртывание, чтобы Production получал заранее проверенный артефакт. Для небольшого проекта можно начать с простого Pipeline: линтер, тесты, сборка и ручной деплой. Затем добавить автоматическую публикацию Docker-образов, Staging, Smoke Tests и управляемый Production Deployment.
Главный принцип: хороший CI/CD должен не просто ускорять выпуск новых версий, а делать каждое развёртывание воспроизводимым, проверяемым и безопасным для пользователей.