380 lines
16 KiB
Markdown
380 lines
16 KiB
Markdown
# 🚀 Документация CI/CD Pipeline NOCR
|
||
|
||
## 📋 Обзор
|
||
|
||
Проект NOCR использует современную многопайплайновую CI/CD систему на базе Drone CI, работающую на Kubernetes. Этот документ описывает 5 специализированных пайплайнов и способы их использования.
|
||
|
||
---
|
||
|
||
## 🎯 Архитектура пайплайнов
|
||
|
||
### Пайплайн 1: **Feature Validation (Валидация функциональных веток)**
|
||
**Триггер:** Push в ветки `feature/*`, `fix/*` или `issues/*`
|
||
**Назначение:** Быстрая обратная связь для разработчиков
|
||
**Длительность:** ~3-5 минут
|
||
|
||
**Что делает:**
|
||
- Клонирует репозиторий с субмодулями
|
||
- Восстанавливает все NuGet-пакеты (общий кэш)
|
||
- Собирает все 4 сервиса в Debug-режиме
|
||
- Запускает unit и integration тесты с Testcontainers
|
||
|
||
**Пример рабочего процесса:**
|
||
```bash
|
||
git checkout -b feature/add-new-filter
|
||
# Внесите изменения...
|
||
git add .
|
||
git commit -m "Add new filter functionality"
|
||
git push origin feature/add-new-filter
|
||
```
|
||
|
||
Drone автоматически запустит тесты. Проверьте результаты перед созданием PR.
|
||
|
||
---
|
||
|
||
### Пайплайн 2: **Main Validation (Валидация основной ветки)**
|
||
**Триггер:** Push в ветку `main`
|
||
**Назначение:** Валидация основной ветки после мерджа
|
||
**Длительность:** ~3-5 минут
|
||
|
||
**Что делает:**
|
||
- То же, что и Feature Validation
|
||
- Гарантирует, что ветка main всегда в рабочем состоянии
|
||
|
||
**Пример рабочего процесса:**
|
||
```bash
|
||
# После мерджа PR в main
|
||
# Пайплайн запускается автоматически
|
||
```
|
||
|
||
---
|
||
|
||
### Пайплайн 3: **Contracts-Only Publish (Публикация только контрактов)**
|
||
**Триггер:** Тег с сообщением коммита, содержащим `contracts_only:<service>`
|
||
**Назначение:** Быстрая публикация NuGet-пакетов контрактов без сборки Docker-образов
|
||
**Длительность:** ~2 минуты
|
||
|
||
**Что делает:**
|
||
- Упаковывает контракты указанного сервиса в NuGet-пакеты
|
||
- Публикует во внутреннем NuGet-фиде
|
||
- Пропускает сборку Docker-образов
|
||
|
||
**Пример рабочего процесса:**
|
||
```bash
|
||
# Обновите контракты telegram-listener
|
||
cd telegram-listener
|
||
# Внесите изменения в Async.Api.Contracts...
|
||
git add .
|
||
git commit -m "contracts_only:telegram_listener - Add MessageEdited event"
|
||
git push origin main
|
||
|
||
# Создайте тег
|
||
git tag v1.2.4-contracts
|
||
git push origin v1.2.4-contracts
|
||
```
|
||
|
||
**Поддерживаемые маркеры:**
|
||
- `contracts_only:telegram_listener`
|
||
- `contracts_only:text_matcher`
|
||
- `contracts_only:users`
|
||
|
||
---
|
||
|
||
### Пайплайн 4: **Full Release (Полный релиз)**
|
||
**Триггер:** Тег на main БЕЗ `contracts_only` или `deploy_only` в сообщении коммита
|
||
**Назначение:** Полный цикл релиза
|
||
**Длительность:** ~8-10 минут
|
||
|
||
**Что делает:**
|
||
1. **Этап 1:** Публикация всех контрактов в NuGet (параллельно)
|
||
2. **Этап 2:** Сборка всех Docker-образов с Kaniko (3 параллельных потока)
|
||
3. **Этап 3:** Деплой в Kubernetes (только для тегов, начинающихся с `v`)
|
||
|
||
**Пример рабочего процесса:**
|
||
```bash
|
||
# Готовы к релизу
|
||
git tag v1.3.0
|
||
git push origin v1.3.0
|
||
|
||
# Drone выполнит:
|
||
# 1. Публикацию контрактов
|
||
# 2. Сборку образов (с тегами v1.3.0, commit SHA, и latest)
|
||
# 3. Деплой в k8s (если тег начинается с 'v')
|
||
```
|
||
|
||
**Создаваемые теги образов:**
|
||
- `hub.musk.fun/k8s/nocr/telegram_listener:v1.3.0`
|
||
- `hub.musk.fun/k8s/nocr/telegram_listener:abc1234` (commit SHA)
|
||
- `hub.musk.fun/k8s/nocr/telegram_listener:latest`
|
||
|
||
---
|
||
|
||
### Пайплайн 5: **Deploy-Only (Только деплой)**
|
||
**Триггер:** Тег с сообщением коммита, содержащим `deploy_only: <version>`
|
||
**Назначение:** Быстрый деплой уже собранных образов
|
||
**Длительность:** ~1 минута
|
||
|
||
**Что делает:**
|
||
- Пропускает сборку
|
||
- Деплоит указанные образы в Kubernetes
|
||
- Полезно для отката или продвижения существующих образов
|
||
|
||
**ВАЖНО:** В сообщении коммита нужно указать версию образов для деплоя:
|
||
|
||
**Пример рабочего процесса:**
|
||
```bash
|
||
# Деплой существующих образов v1.2.9
|
||
git commit --allow-empty -m "deploy_only: v1.2.9"
|
||
git tag deploy-v1.2.9
|
||
git push origin deploy-v1.2.9
|
||
|
||
# Откат на предыдущую версию v1.2.8
|
||
git commit --allow-empty -m "deploy_only: v1.2.8"
|
||
git tag rollback-v1.2.8
|
||
git push origin rollback-v1.2.8
|
||
```
|
||
|
||
**Формат commit message:**
|
||
- `deploy_only: v1.2.9` - деплоит образы с тегом `v1.2.9`
|
||
- Скрипт извлекает версию из сообщения и использует соответствующие образы
|
||
- Образы должны существовать в registry (собраны ранее через full-release)
|
||
|
||
---
|
||
|
||
## 🛠️ Скрипты деплоя
|
||
|
||
Все скрипты деплоя находятся в `_deploy/scripts/`:
|
||
|
||
### `deploy.sh`
|
||
**Назначение:** Деплой сервисов в Kubernetes
|
||
**Использование:**
|
||
```bash
|
||
# Full release (использует TAG для образов)
|
||
./deploy.sh v1.3.0 abc1234
|
||
|
||
# Deploy only (переопределяет тег образа)
|
||
./deploy.sh deploy-v1.2.9 def5678 v1.2.9
|
||
```
|
||
|
||
**Параметры:**
|
||
1. `tag` - Git тег (обязательный)
|
||
2. `commit-sha` - SHA коммита (опциональный)
|
||
3. `image-tag-override` - Переопределение тега образа (опциональный, для deploy_only)
|
||
|
||
**Возможности:**
|
||
- Обновляет deployment-манифесты новыми тегами образов
|
||
- Применяет манифесты в кластер
|
||
- Ожидает завершения rollout с таймаутом
|
||
- Запускает проверки здоровья после деплоя
|
||
- Показывает статус подов
|
||
|
||
### `rollback.sh`
|
||
**Назначение:** Откат деплоев к предыдущей версии
|
||
**Использование:**
|
||
```bash
|
||
# Откат одного сервиса
|
||
./rollback.sh telegram-listener
|
||
|
||
# Откат всех сервисов
|
||
./rollback.sh all
|
||
```
|
||
|
||
**Возможности:**
|
||
- Показывает историю ревизий
|
||
- Выполняет kubectl rollout undo
|
||
- Ожидает завершения отката
|
||
- Запускает проверки здоровья после отката
|
||
|
||
### `health-check.sh`
|
||
**Назначение:** Проверка здоровья всех сервисов NOCR
|
||
**Использование:**
|
||
```bash
|
||
./health-check.sh
|
||
```
|
||
|
||
**Проверяет:**
|
||
- Статус подов (Running/Ready)
|
||
- Health-эндпоинты (/health)
|
||
- Последние события для упавших подов
|
||
|
||
---
|
||
|
||
## 📦 Оптимизации
|
||
|
||
### Общий NuGet-кэш
|
||
Все пайплайны используют общий временный volume для NuGet-пакетов:
|
||
- Первый `dotnet restore` скачивает пакеты
|
||
- Последующие сборки переиспользуют кэшированные пакеты
|
||
- **~60% быстрее**, чем индивидуальное восстановление для каждого сервиса
|
||
|
||
### Параллельное выполнение
|
||
- Публикация контрактов: 3 сервиса параллельно
|
||
- Сборка Docker: 3 параллельных потока
|
||
- Независимые операции никогда не блокируют друг друга
|
||
|
||
### Кэширование Kaniko
|
||
Все сборки Kaniko используют:
|
||
- `--cache=true` - Включено кэширование слоев
|
||
- `--cache-repo=hub.musk.fun/k8s/cache/*` - Общий репозиторий кэша
|
||
- `--compressed-caching=true` - Быстрая передача кэша
|
||
|
||
---
|
||
|
||
## 🧪 Поддержка Testcontainers
|
||
|
||
Пайплайны валидации Feature и Main включают Docker-in-Docker сервис для Testcontainers:
|
||
|
||
```yaml
|
||
services:
|
||
- name: docker
|
||
image: docker:27-dind
|
||
privileged: true
|
||
```
|
||
|
||
Тесты могут использовать Testcontainers для запуска реальных баз данных, очередей сообщений и т.д.
|
||
|
||
---
|
||
|
||
## 🔒 Необходимые секреты
|
||
|
||
Настройте эти секреты в Drone:
|
||
|
||
- `hub_username` - Имя пользователя Docker registry
|
||
- `hub_password` - Пароль Docker registry
|
||
- `nuget_musk_api_key` - API-ключ NuGet-фида
|
||
|
||
---
|
||
|
||
## 📊 Дерево решений пайплайна
|
||
|
||
```
|
||
Push в feature/* → Feature Validation (сборка + тесты)
|
||
Push в main → Main Validation (сборка + тесты)
|
||
|
||
Тег + "contracts_only:" → Contracts Publish
|
||
Тег + "deploy_only:" → Deploy Only
|
||
Тег (без маркеров) → Full Release (контракты → образы → деплой)
|
||
```
|
||
|
||
---
|
||
|
||
## 🎓 Лучшие практики
|
||
|
||
1. **Функциональные ветки**
|
||
- Всегда создавайте функциональные ветки для новой работы
|
||
- Дайте CI валидировать перед мерджем в main
|
||
|
||
2. **Изменения контрактов**
|
||
- Используйте `contracts_only:` для быстрого обновления контрактов
|
||
- Другие сервисы могут сразу обновить ссылки
|
||
|
||
3. **Процесс релиза**
|
||
- Создавайте теги только из ветки main
|
||
- Используйте семантическое версионирование (v1.2.3)
|
||
- Теги, начинающиеся с `v`, автоматически деплоятся в k8s
|
||
|
||
4. **Экстренный откат**
|
||
```bash
|
||
# Быстрый откат через deploy-only
|
||
git commit --allow-empty -m "deploy_only: v1.2.8"
|
||
git tag rollback-v1.2.8
|
||
git push origin rollback-v1.2.8
|
||
|
||
# Или используйте скрипт отката напрямую в кластере
|
||
kubectl exec -it deploy-pod -- bash
|
||
cd /flea/_deploy/scripts
|
||
./rollback.sh all
|
||
```
|
||
|
||
5. **Мониторинг деплоев**
|
||
- Следите за UI Drone для прогресса пайплайна
|
||
- Проверяйте логи подов: `kubectl logs -f deployment/telegram-listener -n nocr`
|
||
- Запускайте проверки здоровья: `./_deploy/scripts/health-check.sh`
|
||
|
||
---
|
||
|
||
## 🐛 Устранение неполадок
|
||
|
||
### Пайплайн завис на "Waiting for contracts"
|
||
**Причина:** Публикация контракта упала
|
||
**Решение:** Проверьте NuGet-фид, проверьте API-ключ
|
||
|
||
### Сборка Docker падает с ошибкой "unauthorized"
|
||
**Причина:** Неверные учетные данные registry
|
||
**Решение:** Обновите секреты `hub_username` и `hub_password`
|
||
|
||
### Тесты падают с ошибкой "Cannot connect to Docker daemon"
|
||
**Причина:** Testcontainers не может достичь Docker-in-Docker сервиса
|
||
**Решение:** Проверьте, что переменная окружения `DOCKER_HOST` установлена правильно
|
||
|
||
### Деплой падает с ошибкой "ImagePullBackOff"
|
||
**Причина:** Образ не найден в registry
|
||
**Решение:** Проверьте, что образ был собран и запушен успешно на предыдущем этапе
|
||
|
||
### YAML-ошибки в .drone.yml
|
||
**Причина:** Неправильное форматирование многострочных команд или двоеточие в переменных
|
||
**Решение:**
|
||
- Используйте блоки `|` для многострочных команд
|
||
- Экранируйте переменные с двоеточиями (например, `"${VAR:0:7}"`)
|
||
- Проверьте YAML: `python3 -c "import yaml; list(yaml.safe_load_all(open('.drone.yml')))"`
|
||
|
||
---
|
||
|
||
## 📚 Дополнительные ресурсы
|
||
|
||
- [Документация Drone CI](https://docs.drone.io/)
|
||
- [Документация Kaniko](https://github.com/GoogleContainerTools/kaniko)
|
||
- [Testcontainers для .NET](https://dotnet.testcontainers.org/)
|
||
- [Kubernetes Deployments](https://kubernetes.io/ru/docs/concepts/workloads/controllers/deployment/)
|
||
|
||
---
|
||
|
||
## 🔄 История изменений (15-16 октября 2025)
|
||
|
||
### Исправлена критическая проблема с YAML
|
||
|
||
**Проблема:**
|
||
- Ошибка `yaml: line 126: mapping values are not allowed in this context`
|
||
- Многострочные команды `/kaniko/executor` содержали переменные с двоеточием (`${DRONE_COMMIT_SHA:0:7}`)
|
||
- YAML парсер интерпретировал двоеточие как разделитель ключ:значение
|
||
|
||
**Решение:**
|
||
1. Обернули все команды `/kaniko/executor` в многострочные блоки с `|`
|
||
2. Добавили обратные слэши `\` для продолжения команды
|
||
3. Экранировали аргументы с двоеточиями в кавычках
|
||
|
||
**Пример:**
|
||
```yaml
|
||
# До (неправильно):
|
||
commands:
|
||
- /kaniko/executor
|
||
--destination=hub.musk.fun/image:${DRONE_COMMIT_SHA:0:7}
|
||
|
||
# После (правильно):
|
||
commands:
|
||
- |
|
||
/kaniko/executor \
|
||
--destination=hub.musk.fun/image:${DRONE_COMMIT_SHA:0:7}
|
||
```
|
||
|
||
### Добавлены новые функции
|
||
|
||
- ✨ Контракты-только пайплайн для быстрой итерации
|
||
- 🚀 Деплой-только пайплайн для откатов
|
||
- 🔄 Обработка MessageEdited событий
|
||
- 📝 Скрипт автокоммита субмодулей
|
||
- ⚡ Оптимизированный общий NuGet-кэш
|
||
- 🔧 Параллельная сборка и деплой
|
||
|
||
---
|
||
|
||
## 📞 Поддержка
|
||
|
||
Если у вас возникли проблемы с CI/CD:
|
||
1. Проверьте логи в Drone UI: https://drone.musk.fun/nocr/flea
|
||
2. Проверьте статус подов: `kubectl get pods -n nocr`
|
||
3. Запустите health-check: `./health-check.sh`
|
||
4. Проверьте логи контейнеров: `kubectl logs -f <pod-name> -n nocr`
|
||
|
||
Для вопросов по инфраструктуре обращайтесь к DevOps-команде.
|