Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Кейс: Микросервисы
case_microservices

Кейс: Микросервисы

Оркестрация пайплайнов для микросервисной архитектуры, monorepo vs multirepo.

Кейс: Микросервисы

Оркестрация пайплайнов для микросервисной архитектуры: monorepo vs multirepo, reusable workflows, service mesh, API gateway.

#Введение

В этом кейсе мы рассмотрим настройку CI/CD для микросервисной архитектуры. Вы изучите:

  • Выбор между monorepo и multirepo подходами
  • Оркестрацию пайплайнов с зависимостями между сервисами
  • Reusable workflows для централизованного управления CI/CD
  • Интеграцию с API Gateway и Service Mesh
  • Canary деплой и управление трафиком

#Monorepo vs Multirepo

#Monorepo подход

Все сервисы хранятся в одном репозитории:

my-company/
├── services/
│   ├── api-gateway/
│   ├── user-service/
│   ├── order-service/
│   └── notification-service/
├── shared/
│   ├── types/
│   ├── utils/
│   └── proto/
├── infrastructure/
│   ├── terraform/
│   └── kubernetes/
└── .github/
    └── workflows/
        ├── ci.yml
        └── deploy.yml

Преимущества monorepo:

  • Единая история коммитов
  • Упрощённые кросс-сервисные изменения
  • Общие зависимости и версии
  • Централизованный CI/CD

Недостатки monorepo:

  • Большой размер репозитория
  • Сложность с permissions (все имеют доступ ко всему)
  • Риск coupling между сервисами

#Multirepo подход

Каждый сервис в отдельном репозитории:

myorg-api-gateway/
myorg-user-service/
myorg-order-service/
myorg-notification-service/
myorg-infra/

Преимущества multirepo:

  • Независимый CI/CD для каждого сервиса
  • Изолированные permissions
  • Чёткие границы сервисов
  • Меньший размер каждого репозитория

Недостатки multirepo:

  • Сложность кросс-сервисных изменений
  • Дублирование CI/CD конфигурации
  • Сложнее отслеживать совместимость версий

#Гибридный подход

Используйте monorepo для связанных сервисов одной команды, multirepo для независимых сервисов разных команд.

#Reusable Workflows

#Создание reusable workflow

# .github/workflows/reusable-ci.yml в репозитории myorg/.github name: Reusable CI on: workflow_call: inputs: node-version: required: false type: string default: '20' test-command: required: false type: string default: 'npm test' coverage-enabled: required: false type: boolean default: false jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: 'npm' - name: Install dependencies run: npm ci - name: Run ESLint run: npm run lint - name: Run TypeScript check run: npm run typecheck test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} cache: 'npm' - name: Install dependencies run: npm ci - name: Run tests run: ${{ inputs.test-command }} - name: Upload coverage if: inputs.coverage-enabled uses: codecov/codecov-action@v4

#Вызов reusable workflow из сервиса

# services/user-service/.github/workflows/ci.yml name: User Service CI on: push: branches: [main] pull_request: branches: [main] jobs: ci: uses: myorg/.github/.github/workflows/reusable-ci.yml@main with: node-version: '20' test-command: 'npm test' coverage-enabled: true

#Преимущества reusable workflows

  1. Единая точка изменения — обновил workflow в .github, применилось ко всем сервисам
  2. Стандартизация — все сервисы используют одинаковый CI процесс
  3. Безопасность — централизованный контроль над секретами и permissions

#Path-based триггеры в monorepo

#Запуск тестов только для изменённых сервисов

# .github/workflows/ci-monorepo.yml name: Monorepo CI on: push: branches: [main] pull_request: branches: [main] jobs: detect-changes: runs-on: ubuntu-latest outputs: user-service: ${{ steps.filter.outputs.user-service }} order-service: ${{ steps.filter.outputs.order-service }} api-gateway: ${{ steps.filter.outputs.api-gateway }} steps: - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3 id: filter with: filters: | user-service: - 'services/user-service/**' - 'shared/**' order-service: - 'services/order-service/**' - 'shared/**' api-gateway: - 'services/api-gateway/**' - 'shared/**' test-user-service: needs: detect-changes if: needs.detect-changes.outputs.user-service == 'true' runs-on: ubuntu-latest defaults: run: working-directory: services/user-service steps: - uses: actions/checkout@v4 - name: Run tests run: npm test test-order-service: needs: detect-changes if: needs.detect-changes.outputs.order-service == 'true' runs-on: ubuntu-latest defaults: run: working-directory: services/order-service steps: - uses: actions/checkout@v4 - name: Run tests run: npm test

#Action dorny/paths-filter

Определяет изменённые пути и создаёт булевы флаги для conditional jobs:

- uses: dorny/paths-filter@v3 id: filter with: filters: | backend: - 'backend/**' frontend: - 'frontend/**' docs: - 'docs/**' - '*.md'

#Dependency graph и оркестрация деплоя

#Построение графа зависимостей

┌─────────────────┐
│   API Gateway   │
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
┌───▼───┐ ┌──▼──────┐
│ User  │ │ Order   │
│Service│ │ Service │
└───┬───┘ └────┬────┘
    │          │
    │     ┌────▼────────┐
    │     │ Notification│
    │     │  Service    │
    │     └─────────────┘
    │
┌───▼─────────┐
│  Database   │
└─────────────┘

#DAG (Directed Acyclic Graph) в GitHub Actions

# .github/workflows/deploy-all.yml name: Deploy All Services on: push: branches: [main] jobs: deploy-database: runs-on: ubuntu-latest steps: - name: Deploy database migrations run: ./scripts/deploy-db.sh deploy-user-service: needs: deploy-database runs-on: ubuntu-latest steps: - name: Deploy user-service run: ./scripts/deploy-user-service.sh deploy-order-service: needs: [deploy-database, deploy-user-service] runs-on: ubuntu-latest steps: - name: Deploy order-service run: ./scripts/deploy-order-service.sh deploy-notification-service: needs: deploy-order-service runs-on: ubuntu-latest steps: - name: Deploy notification-service run: ./scripts/deploy-notification-service.sh deploy-api-gateway: needs: [deploy-user-service, deploy-order-service, deploy-notification-service] runs-on: ubuntu-latest steps: - name: Deploy api-gateway run: ./scripts/deploy-api-gateway.sh

#Порядок деплоя

  1. Database — миграции БД
  2. User Service — базовый сервис, от которого зависят другие
  3. Order Service — зависит от User Service
  4. Notification Service — зависит от Order Service
  5. API Gateway — маршрутизирует ко всем сервисам, деплоится последним

#Версионирование API

#Semantic Versioning (Semver)

MAJOR.MINOR.PATCH
  │     │     │
  │     │     └─ обратно совместимые исправления
  │     └─────── обратно совместимые новые функции
  └───────────── breaking changes

#Автоматическое определение версии

# .github/workflows/release.yml name: Release on: push: branches: [main] jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install semantic-release run: npm install -g semantic-release - name: Run semantic-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: npx semantic-release

#.releaserc.json

{ "branches": ["main"], "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm", "@semantic-release/github" ] }

#Conventional Commits

feat: добавить новую функцию          # MINOR
fix: исправить ошибку                 # PATCH
BREAKING CHANGE: изменить API         # MAJOR

#API Gateway

#Kong API Gateway

# kubernetes/kong-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: api-gateway annotations: konghq.com/plugins: rate-limiting konghq.com/strip-path: "true" spec: rules: - host: api.example.com http: paths: - path: /users pathType: Prefix backend: service: name: user-service port: 80 - path: /orders pathType: Prefix backend: service: name: order-service port: 80 - path: /notifications pathType: Prefix backend: service: name: notification-service port: 80

#Kong Plugin для rate limiting

# kubernetes/kong-plugin.yaml apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: rate-limiting config: minute: 100 policy: local plugin: rate-limiting

#Деплой API Gateway в пайплайне

# .github/workflows/deploy-gateway.yml name: Deploy API Gateway on: push: branches: [main] paths: - 'services/api-gateway/**' jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build and push image uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/myorg/api-gateway:${{ github.sha }} - name: Deploy to Kubernetes run: | kubectl set image deployment/api-gateway \ api-gateway=ghcr.io/myorg/api-gateway:${{ github.sha }} \ -n production - name: Wait for rollout run: | kubectl rollout status deployment/api-gateway -n production - name: Update Kong routes run: | kubectl apply -f kubernetes/kong-routes.yaml

#Service Mesh (Istio)

#Установка Istio

# .github/workflows/setup-istio.yml name: Setup Istio on: workflow_dispatch: jobs: install: runs-on: ubuntu-latest steps: - name: Install Istio run: | istioctl install --set profile=default -y - name: Enable sidecar injection run: | kubectl label namespace production istio-injection=enabled

#VirtualService для canary деплоя

# kubernetes/virtual-service.yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: user-service spec: hosts: - user-service http: - route: - destination: host: user-service subset: stable weight: 90 - destination: host: user-service subset: canary weight: 10

#DestinationRule для версий

# kubernetes/destination-rule.yaml apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: user-service spec: host: user-service subsets: - name: stable labels: version: stable - name: canary labels: version: canary

#Canary деплой

#Workflow для canary деплоя

# .github/workflows/canary-deploy.yml name: Canary Deploy on: push: branches: [main] paths: - 'services/user-service/**' jobs: canary: runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - name: Build and push canary image uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/myorg/user-service:canary-${{ github.sha }} - name: Deploy canary version run: | kubectl apply -f kubernetes/user-service-canary.yaml kubectl set image deployment/user-service-canary \ user-service=ghcr.io/myorg/user-service:canary-${{ github.sha }} \ -n production - name: Configure Istio traffic split run: | kubectl apply -f kubernetes/virtual-service-canary.yaml - name: Wait for canary pods run: | kubectl wait --for=condition=available deployment/user-service-canary -n production --timeout=300s - name: Run smoke tests run: | ./scripts/smoke-tests.sh --canary - name: Monitor metrics (5 minutes) run: | ./scripts/monitor-canary.sh --duration=300 - name: Promote to stable or rollback if: always() run: | if [ "${{ job.status }}" == "success" ]; then ./scripts/promote-canary.sh else ./scripts/rollback-canary.sh fi

#Скрипт мониторинга canary

#!/bin/bash # scripts/monitor-canary.sh DURATION=${1:-300} ERROR_THRESHOLD=1 LATENCY_THRESHOLD=500 echo "Monitoring canary for $DURATION seconds..." START_TIME=$(date +%s) END_TIME=$((START_TIME + DURATION)) while [ $(date +%s) -lt $END_TIME ]; do ERROR_RATE=$(curl -s http://prometheus/api/v1/query?query=rate(http_requests_total{status="500",service="user-service-canary"}[1m]) | jq '.data.result[0].value[1]') LATENCY=$(curl -s http://prometheus/api/v1/query?query=histogram_quantile(0.95,rate(http_request_duration_seconds_bucket{service="user-service-canary"}[1m])) | jq '.data.result[0].value[1]') echo "Error rate: $ERROR_RATE%, Latency: $LATENCY ms" if (( $(echo "$ERROR_RATE > $ERROR_THRESHOLD" | bc -l) )); then echo "Error rate exceeded threshold!" exit 1 fi if (( $(echo "$LATENCY > $LATENCY_THRESHOLD" | bc -l) )); then echo "Latency exceeded threshold!" exit 1 fi sleep 10 done echo "Canary monitoring passed!"

#Управление конфигурацией

#ConfigMap для разных окружений

# kubernetes/configmap-staging.yaml apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: staging data: API_URL: "https://staging-api.example.com" LOG_LEVEL: "debug" ENABLE_METRICS: "true"
# kubernetes/configmap-production.yaml apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: production data: API_URL: "https://api.example.com" LOG_LEVEL: "info" ENABLE_METRICS: "true"

#External Secrets Operator

# kubernetes/external-secret.yaml apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-secrets namespace: production spec: refreshInterval: 1h secretStoreRef: name: aws-secrets-manager kind: ClusterSecretStore target: name: app-secrets data: - secretKey: DATABASE_URL remoteRef: key: myapp/production/database property: url - secretKey: API_KEY remoteRef: key: myapp/production/api property: key

#Helm values для окружений

# helm/values-staging.yaml replicaCount: 1 resources: limits: cpu: 200m memory: 256Mi environment: staging logLevel: debug
# helm/values-production.yaml replicaCount: 3 resources: limits: cpu: 500m memory: 512Mi environment: production logLevel: info autoscaling: enabled: true minReplicas: 3 maxReplicas: 10

#Мониторинг и observability

#Prometheus metrics

# kubernetes/servicemonitor.yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: user-service namespace: production spec: selector: matchLabels: app: user-service endpoints: - port: http path: /metrics interval: 30s

#Grafana dashboard

# kubernetes/grafana-dashboard.yaml apiVersion: v1 kind: ConfigMap metadata: name: grafana-dashboard namespace: monitoring data: microservices.json: | { "dashboard": { "title": "Microservices Overview", "panels": [ { "title": "Request Rate", "targets": [ { "expr": "rate(http_requests_total[5m])" } ] }, { "title": "Error Rate", "targets": [ { "expr": "rate(http_requests_total{status=~\"5..\"}[5m])" } ] } ] } }

#Distributed tracing (Jaeger)

# kubernetes/jaeger.yaml apiVersion: jaegertracing.io/v1 kind: Jaeger metadata: name: production spec: strategy: production collector: options: log-level: info query: options: log-level: info storage: type: elasticsearch options: es: server-urls: http://elasticsearch:9200

#Резюме

CI/CD для микросервисов включает:

  1. Архитектура репозиториев

    • Monorepo — централизованное управление, проще кросс-сервисные изменения
    • Multirepo — независимость сервисов, изолированный CI/CD
  2. Reusable workflows

    • Централизованное управление CI/CD логикой
    • Стандартизация процессов across all services
  3. Оркестрация деплоя

    • DAG для определения порядка деплоя
    • Path-based триггеры для запуска только изменённых сервисов
  4. API Gateway

    • Единая точка входа
    • Маршрутизация, аутентификация, rate limiting
  5. Service Mesh (Istio)

    • Управление трафиком между сервисами
    • Canary деплой, traffic shifting
    • mTLS для безопасности
  6. Версионирование

    • Semantic versioning для API
    • Автоматическое определение версии через conventional commits
  7. Мониторинг

    • Prometheus metrics
    • Grafana dashboards
    • Distributed tracing (Jaeger)