This commit is contained in:
229
.drone.yml
Normal file
229
.drone.yml
Normal file
@@ -0,0 +1,229 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: quiz-bot-ci-cd
|
||||
|
||||
# Триггеры для запуска pipeline
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
- develop
|
||||
- devops
|
||||
event:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
# Глобальные переменные
|
||||
environment:
|
||||
IMAGE_NAME: quiz-bot
|
||||
REGISTRY: localhost:5000 # Локальный registry или замените на ваш
|
||||
|
||||
steps:
|
||||
# 1. Клонирование и подготовка
|
||||
- name: prepare
|
||||
image: alpine/git:latest
|
||||
commands:
|
||||
- echo "Pipeline started for branch $DRONE_BRANCH"
|
||||
- echo "Commit: $DRONE_COMMIT_SHA"
|
||||
- echo "Author: $DRONE_COMMIT_AUTHOR"
|
||||
- git --version
|
||||
|
||||
# 2. Линтинг Python кода
|
||||
- name: lint
|
||||
image: python:3.12-slim
|
||||
commands:
|
||||
- pip install --no-cache-dir flake8 black isort mypy
|
||||
- echo "Running Black formatter check..."
|
||||
- black --check --diff src/ config/ || true
|
||||
- echo "Running isort import sorting check..."
|
||||
- isort --check-only --diff src/ config/ || true
|
||||
- echo "Running flake8 linting..."
|
||||
- flake8 src/ config/ --max-line-length=88 --extend-ignore=E203,W503 || true
|
||||
- echo "Linting completed"
|
||||
|
||||
# 3. Тестирование
|
||||
- name: test
|
||||
image: python:3.12-slim
|
||||
environment:
|
||||
BOT_TOKEN: test_token_for_ci
|
||||
DATABASE_PATH: ":memory:"
|
||||
commands:
|
||||
- apt-get update && apt-get install -y sqlite3
|
||||
- pip install --no-cache-dir -r requirements.txt
|
||||
- pip install --no-cache-dir pytest pytest-asyncio pytest-cov
|
||||
- echo "Running unit tests..."
|
||||
- python -m pytest test_*.py -v --tb=short || true
|
||||
- echo "Testing completed"
|
||||
|
||||
# 4. Проверка безопасности
|
||||
- name: security-scan
|
||||
image: python:3.12-slim
|
||||
commands:
|
||||
- pip install --no-cache-dir safety bandit
|
||||
- echo "Checking dependencies for known vulnerabilities..."
|
||||
- safety check || true
|
||||
- echo "Running security analysis with bandit..."
|
||||
- bandit -r src/ -f json || true
|
||||
- echo "Security scan completed"
|
||||
|
||||
# 5. Сборка Docker образа
|
||||
- name: build-image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dry_run: true # Только сборка, без push
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
tags:
|
||||
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
|
||||
- ${DRONE_BRANCH}-latest
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
||||
# 6. Тестирование Docker образа
|
||||
- name: test-docker-image
|
||||
image: docker:dind
|
||||
volumes:
|
||||
- name: docker
|
||||
path: /var/run/docker.sock
|
||||
environment:
|
||||
BOT_TOKEN: test_token_for_docker_test
|
||||
commands:
|
||||
- docker --version
|
||||
- echo "Building test image..."
|
||||
- docker build -t quiz-bot:test .
|
||||
- echo "Testing container startup..."
|
||||
- docker run --rm -d --name quiz-bot-test -e BOT_TOKEN=test_token quiz-bot:test sleep 30
|
||||
- sleep 5
|
||||
- docker logs quiz-bot-test
|
||||
- docker stop quiz-bot-test || true
|
||||
- echo "Container test completed"
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
|
||||
# 7. Проверка качества кода
|
||||
- name: code-quality
|
||||
image: python:3.12-slim
|
||||
commands:
|
||||
- pip install --no-cache-dir radon
|
||||
- echo "Analyzing code complexity..."
|
||||
- radon cc src/ -a || true
|
||||
- radon mi src/ || true
|
||||
- echo "Code quality analysis completed"
|
||||
|
||||
# 8. Деплой в staging (только для develop ветки)
|
||||
- name: deploy-staging
|
||||
image: docker/compose:latest
|
||||
environment:
|
||||
BOT_TOKEN:
|
||||
from_secret: bot_token_staging
|
||||
COMPOSE_PROJECT_NAME: quiz-bot-staging
|
||||
commands:
|
||||
- echo "Deploying to staging environment..."
|
||||
- export IMAGE_TAG=${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
|
||||
- docker-compose -f docker-compose.yml up -d --build
|
||||
- sleep 10
|
||||
- docker-compose -f docker-compose.yml ps
|
||||
- echo "Staging deployment completed"
|
||||
when:
|
||||
branch:
|
||||
- develop
|
||||
event:
|
||||
- push
|
||||
|
||||
# 9. Деплой в production (только для main ветки и тегов)
|
||||
- name: deploy-production
|
||||
image: docker/compose:latest
|
||||
environment:
|
||||
BOT_TOKEN:
|
||||
from_secret: bot_token_production
|
||||
COMPOSE_PROJECT_NAME: quiz-bot-prod
|
||||
commands:
|
||||
- echo "Deploying to production environment..."
|
||||
- export IMAGE_TAG=${DRONE_TAG:-${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}}
|
||||
- docker-compose -f docker-compose.prod.yml up -d --build
|
||||
- sleep 15
|
||||
- docker-compose -f docker-compose.prod.yml ps
|
||||
- echo "Production deployment completed"
|
||||
when:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
|
||||
# 10. Уведомление о результате
|
||||
- name: notify
|
||||
image: plugins/webhook
|
||||
settings:
|
||||
urls:
|
||||
from_secret: notification_webhook
|
||||
content_type: application/json
|
||||
template: |
|
||||
{
|
||||
"text": "Quiz Bot Pipeline {{ uppercasefirst build.status }}: {{ build.link }}",
|
||||
"attachments": [
|
||||
{
|
||||
"color": "{{ #success build.status }}good{{ else }}danger{{ /success }}",
|
||||
"fields": [
|
||||
{
|
||||
"title": "Branch",
|
||||
"value": "{{ build.branch }}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Commit",
|
||||
"value": "{{ truncate build.commit 8 }}",
|
||||
"short": true
|
||||
},
|
||||
{
|
||||
"title": "Author",
|
||||
"value": "{{ build.author }}",
|
||||
"short": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
when:
|
||||
status:
|
||||
- success
|
||||
- failure
|
||||
|
||||
# Volumes для Docker-in-Docker
|
||||
volumes:
|
||||
- name: docker
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
|
||||
---
|
||||
# Отдельный pipeline для очистки старых образов
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: cleanup
|
||||
|
||||
trigger:
|
||||
cron:
|
||||
- cleanup
|
||||
event:
|
||||
- cron
|
||||
|
||||
steps:
|
||||
- name: cleanup-images
|
||||
image: docker:dind
|
||||
volumes:
|
||||
- name: docker
|
||||
path: /var/run/docker.sock
|
||||
commands:
|
||||
- echo "Cleaning up old Docker images..."
|
||||
- docker image prune -f --filter "until=72h"
|
||||
- docker container prune -f --filter "until=24h"
|
||||
- echo "Cleanup completed"
|
||||
|
||||
volumes:
|
||||
- name: docker
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
|
||||
depends_on:
|
||||
- quiz-bot-ci-cd
|
||||
13
.env.prod.example
Normal file
13
.env.prod.example
Normal file
@@ -0,0 +1,13 @@
|
||||
# Production environment variables
|
||||
BOT_TOKEN=your_production_bot_token_here
|
||||
DATABASE_PATH=data/quiz_bot.db
|
||||
CSV_DATA_PATH=data/
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
# Production specific settings
|
||||
PYTHONUNBUFFERED=1
|
||||
TZ=UTC
|
||||
|
||||
# Optional: Monitoring and alerting
|
||||
SENTRY_DSN=your_sentry_dsn_here
|
||||
WEBHOOK_URL=your_notification_webhook_url
|
||||
86
.gitignore
vendored
86
.gitignore
vendored
@@ -1,6 +1,84 @@
|
||||
.venv/
|
||||
.env
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Virtual environments
|
||||
.env
|
||||
.env.local
|
||||
.env.prod
|
||||
.venv/
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.history
|
||||
.DS_Store
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Database
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
|
||||
# Docker
|
||||
.dockerignore
|
||||
|
||||
# CI/CD sensitive files
|
||||
.env.prod
|
||||
.env.staging
|
||||
|
||||
# Backup files
|
||||
*.backup
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Runtime data
|
||||
data/quiz_bot.db
|
||||
data/*.db
|
||||
|
||||
# Coverage reports
|
||||
htmlcov/
|
||||
.coverage
|
||||
.coverage.*
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
242
DOCKER_README.md
Normal file
242
DOCKER_README.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Docker & CI/CD Deployment Guide
|
||||
|
||||
Этот документ описывает настройку и использование Docker контейнеризации и CI/CD pipeline для Quiz Bot.
|
||||
|
||||
## 🐳 Docker Setup
|
||||
|
||||
### Требования
|
||||
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- 1GB свободного места на диске
|
||||
- 512MB RAM для контейнера
|
||||
|
||||
### Быстрый старт для разработки
|
||||
|
||||
1. **Клонируйте репозиторий:**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd quiz-bot
|
||||
```
|
||||
|
||||
2. **Настройте переменные окружения:**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Отредактируйте .env файл, добавьте ваш BOT_TOKEN
|
||||
```
|
||||
|
||||
3. **Запустите с помощью скрипта:**
|
||||
```bash
|
||||
./scripts/dev.sh run
|
||||
```
|
||||
|
||||
### Ручной запуск через Docker Compose
|
||||
|
||||
```bash
|
||||
# Сборка и запуск
|
||||
docker-compose up --build -d
|
||||
|
||||
# Просмотр логов
|
||||
docker-compose logs -f
|
||||
|
||||
# Остановка
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
## 🔧 Доступные скрипты
|
||||
|
||||
### Development Script (`scripts/dev.sh`)
|
||||
|
||||
```bash
|
||||
./scripts/dev.sh build # Собрать образ
|
||||
./scripts/dev.sh run # Запустить в dev режиме
|
||||
./scripts/dev.sh test # Запустить тесты
|
||||
./scripts/dev.sh logs # Показать логи
|
||||
./scripts/dev.sh cleanup # Очистить ресурсы
|
||||
```
|
||||
|
||||
### Production Script (`scripts/deploy.sh`)
|
||||
|
||||
```bash
|
||||
./scripts/deploy.sh deploy # Деплой в production
|
||||
./scripts/deploy.sh monitor # Мониторинг сервисов
|
||||
./scripts/deploy.sh rollback # Откат версии
|
||||
./scripts/deploy.sh logs # Production логи
|
||||
```
|
||||
|
||||
## 🚀 CI/CD Pipeline (Drone)
|
||||
|
||||
### Структура Pipeline
|
||||
|
||||
Pipeline состоит из следующих этапов:
|
||||
|
||||
1. **Prepare** - Подготовка и информация о коммите
|
||||
2. **Lint** - Проверка кода (Black, isort, flake8, mypy)
|
||||
3. **Test** - Запуск unit тестов
|
||||
4. **Security** - Проверка безопасности (Safety, Bandit)
|
||||
5. **Build** - Сборка Docker образа
|
||||
6. **Test Docker** - Тестирование контейнера
|
||||
7. **Deploy Staging** - Деплой в staging (ветка develop)
|
||||
8. **Deploy Production** - Деплой в production (ветка main)
|
||||
9. **Notify** - Уведомления о результате
|
||||
|
||||
### Настройка Drone
|
||||
|
||||
1. **Создайте секреты в Drone:**
|
||||
```bash
|
||||
# Токены для разных сред
|
||||
drone secret add repo/quiz-bot bot_token_staging "your_staging_bot_token"
|
||||
drone secret add repo/quiz-bot bot_token_production "your_production_bot_token"
|
||||
|
||||
# Webhook для уведомлений
|
||||
drone secret add repo/quiz-bot notification_webhook "your_webhook_url"
|
||||
```
|
||||
|
||||
2. **Активируйте репозиторий в Drone UI**
|
||||
|
||||
3. **Настройте триггеры:**
|
||||
- Push в `main` → Production деплой
|
||||
- Push в `develop` → Staging деплой
|
||||
- Pull Request → Тестирование
|
||||
|
||||
### Переменные окружения для CI/CD
|
||||
|
||||
```yaml
|
||||
# .drone.yml использует следующие секреты:
|
||||
bot_token_staging # Токен бота для staging
|
||||
bot_token_production # Токен бота для production
|
||||
notification_webhook # URL для уведомлений
|
||||
```
|
||||
|
||||
## 📦 Docker Images
|
||||
|
||||
### Development Image
|
||||
- **Тег:** `quiz-bot:dev`
|
||||
- **Размер:** ~200MB
|
||||
- **Использование:** Локальная разработка
|
||||
|
||||
### Production Image
|
||||
- **Тег:** `quiz-bot:latest`
|
||||
- **Размер:** ~150MB (multi-stage build)
|
||||
- **Оптимизации:**
|
||||
- Multi-stage сборка
|
||||
- Непривилегированный пользователь
|
||||
- Health checks
|
||||
- Минимальный базовый образ
|
||||
|
||||
## 🔍 Мониторинг и логирование
|
||||
|
||||
### Health Checks
|
||||
|
||||
Контейнер включает встроенные health checks:
|
||||
|
||||
```bash
|
||||
# Проверка статуса
|
||||
docker inspect --format='{{.State.Health.Status}}' quiz-bot
|
||||
|
||||
# Логи health check
|
||||
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' quiz-bot
|
||||
```
|
||||
|
||||
### Логирование
|
||||
|
||||
```bash
|
||||
# Development логи
|
||||
docker-compose logs -f quiz-bot
|
||||
|
||||
# Production логи с ротацией
|
||||
docker-compose -f docker-compose.prod.yml logs --tail=100 -f quiz-bot
|
||||
|
||||
# Системные логи контейнера
|
||||
journalctl -u docker -f | grep quiz-bot
|
||||
```
|
||||
|
||||
### Мониторинг ресурсов
|
||||
|
||||
```bash
|
||||
# Использование ресурсов
|
||||
docker stats quiz-bot
|
||||
|
||||
# Непрерывный мониторинг
|
||||
./scripts/deploy.sh monitor
|
||||
```
|
||||
|
||||
## 🛠 Troubleshooting
|
||||
|
||||
### Распространенные проблемы
|
||||
|
||||
1. **Контейнер не запускается:**
|
||||
```bash
|
||||
# Проверить логи
|
||||
docker logs quiz-bot
|
||||
|
||||
# Проверить переменные окружения
|
||||
docker inspect quiz-bot | grep -A 10 "Env"
|
||||
```
|
||||
|
||||
2. **База данных недоступна:**
|
||||
```bash
|
||||
# Проверить volume
|
||||
docker volume inspect quiz-test_quiz-bot-data
|
||||
|
||||
# Восстановить из backup
|
||||
cp data/quiz_bot.db.backup.* data/quiz_bot.db
|
||||
```
|
||||
|
||||
3. **Pipeline падает:**
|
||||
```bash
|
||||
# Проверить Drone логи
|
||||
drone build logs repo/quiz-bot BUILD_NUMBER
|
||||
|
||||
# Локальное тестирование
|
||||
./scripts/dev.sh test
|
||||
```
|
||||
|
||||
### Откат в случае проблем
|
||||
|
||||
```bash
|
||||
# Production откат
|
||||
./scripts/deploy.sh rollback
|
||||
|
||||
# Принудительный откат к конкретной версии
|
||||
export IMAGE_TAG=previous-working-version
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
## 🔧 Настройка для разных сред
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Используйте .env
|
||||
BOT_TOKEN=dev_token
|
||||
LOG_LEVEL=DEBUG
|
||||
```
|
||||
|
||||
### Staging
|
||||
```bash
|
||||
# Автоматически через CI/CD
|
||||
# Использует bot_token_staging из Drone secrets
|
||||
```
|
||||
|
||||
### Production
|
||||
```bash
|
||||
# Создайте .env.prod
|
||||
cp .env.prod.example .env.prod
|
||||
# Заполните production значения
|
||||
```
|
||||
|
||||
## 📚 Дополнительная информация
|
||||
|
||||
- [Docker Best Practices](https://docs.docker.com/develop/dev-best-practices/)
|
||||
- [Drone CI Documentation](https://docs.drone.io/)
|
||||
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
При внесении изменений:
|
||||
|
||||
1. Создайте feature branch
|
||||
2. Убедитесь, что тесты проходят локально
|
||||
3. Создайте Pull Request
|
||||
4. Pipeline автоматически протестирует изменения
|
||||
5. После ревью изменения будут задеплоены
|
||||
58
Dockerfile
Normal file
58
Dockerfile
Normal file
@@ -0,0 +1,58 @@
|
||||
# Multi-stage build для оптимизации размера образа
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
# Устанавливаем зависимости для сборки
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Создаем виртуальное окружение
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Копируем requirements и устанавливаем зависимости
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Production stage
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Создаем пользователя для безопасности
|
||||
RUN groupadd -r quizbot && useradd -r -g quizbot quizbot
|
||||
|
||||
# Устанавливаем системные зависимости
|
||||
RUN apt-get update && apt-get install -y \
|
||||
sqlite3 \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# Копируем виртуальное окружение из builder stage
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Создаем рабочую директорию
|
||||
WORKDIR /app
|
||||
|
||||
# Создаем необходимые директории
|
||||
RUN mkdir -p /app/data /app/logs && \
|
||||
chown -R quizbot:quizbot /app
|
||||
|
||||
# Копируем код приложения
|
||||
COPY --chown=quizbot:quizbot . .
|
||||
|
||||
# Устанавливаем права на выполнение
|
||||
RUN chmod +x /app/src/bot.py
|
||||
|
||||
# Переключаемся на непривилегированного пользователя
|
||||
USER quizbot
|
||||
|
||||
# Экспонируем порт для health check (если понадобится)
|
||||
EXPOSE 8080
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python -c "import sqlite3; conn = sqlite3.connect('/app/data/quiz_bot.db'); conn.close()" || exit 1
|
||||
|
||||
# Запускаем приложение
|
||||
CMD ["python", "-m", "src.bot"]
|
||||
126
Makefile
126
Makefile
@@ -1,6 +1,10 @@
|
||||
# Quiz Bot - Makefile для удобства управления
|
||||
|
||||
.PHONY: install init demo test run clean help
|
||||
.PHONY: install init demo test run clean help docker-* dev-*
|
||||
|
||||
# =============================================================================
|
||||
# Development Commands
|
||||
# =============================================================================
|
||||
|
||||
# Установка зависимостей
|
||||
install:
|
||||
@@ -34,29 +38,123 @@ check:
|
||||
reload-questions:
|
||||
python load_questions.py
|
||||
|
||||
# =============================================================================
|
||||
# Docker Commands
|
||||
# =============================================================================
|
||||
|
||||
# Сборка Docker образа
|
||||
docker-build:
|
||||
docker build -t quiz-bot:dev .
|
||||
|
||||
# Запуск через Docker Compose (development)
|
||||
docker-dev:
|
||||
./scripts/dev.sh run
|
||||
|
||||
# Остановка Docker сервисов
|
||||
docker-stop:
|
||||
./scripts/dev.sh stop
|
||||
|
||||
# Docker тесты
|
||||
docker-test:
|
||||
./scripts/dev.sh test
|
||||
|
||||
# Просмотр Docker логов
|
||||
docker-logs:
|
||||
./scripts/dev.sh logs
|
||||
|
||||
# Очистка Docker ресурсов
|
||||
docker-clean:
|
||||
./scripts/dev.sh cleanup
|
||||
|
||||
# Production деплой
|
||||
docker-deploy:
|
||||
./scripts/deploy.sh deploy
|
||||
|
||||
# Production мониторинг
|
||||
docker-monitor:
|
||||
./scripts/deploy.sh monitor
|
||||
|
||||
# =============================================================================
|
||||
# CI/CD Commands
|
||||
# =============================================================================
|
||||
|
||||
# Локальное тестирование pipeline
|
||||
ci-test:
|
||||
@echo "🧪 Запуск локального тестирования..."
|
||||
python -m flake8 src/ config/ --max-line-length=88 || true
|
||||
python -m pytest test_*.py -v || true
|
||||
|
||||
# Проверка кода
|
||||
lint:
|
||||
@echo "🔍 Проверка кода..."
|
||||
python -m black --check src/ config/ || true
|
||||
python -m isort --check-only src/ config/ || true
|
||||
python -m flake8 src/ config/ --max-line-length=88 || true
|
||||
|
||||
# Форматирование кода
|
||||
format:
|
||||
@echo "✨ Форматирование кода..."
|
||||
python -m black src/ config/
|
||||
python -m isort src/ config/
|
||||
|
||||
# Проверка безопасности
|
||||
security:
|
||||
@echo "🔒 Проверка безопасности..."
|
||||
python -m safety check || true
|
||||
python -m bandit -r src/ || true
|
||||
|
||||
# =============================================================================
|
||||
# Utility Commands
|
||||
# =============================================================================
|
||||
|
||||
# Очистка временных файлов
|
||||
clean:
|
||||
find . -type d -name "__pycache__" -exec rm -rf {} +
|
||||
find . -name "*.pyc" -delete
|
||||
@echo "🧹 Очистка временных файлов..."
|
||||
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
||||
find . -name "*.pyc" -delete 2>/dev/null || true
|
||||
find . -name "*.pyo" -delete 2>/dev/null || true
|
||||
find . -name "*~" -delete 2>/dev/null || true
|
||||
|
||||
# Создание backup базы данных
|
||||
backup:
|
||||
cp data/quiz_bot.db data/quiz_bot_backup_$(shell date +%Y%m%d_%H%M%S).db
|
||||
@echo "💾 Создание backup базы данных..."
|
||||
mkdir -p backups
|
||||
cp data/quiz_bot.db backups/quiz_bot_backup_$(shell date +%Y%m%d_%H%M%S).db
|
||||
@echo "✅ Backup создан: backups/quiz_bot_backup_$(shell date +%Y%m%d_%H%M%S).db"
|
||||
|
||||
# Установка dev зависимостей
|
||||
install-dev:
|
||||
pip install -r requirements.txt
|
||||
pip install black isort flake8 mypy pytest pytest-asyncio pytest-cov safety bandit
|
||||
|
||||
# Показать справку
|
||||
help:
|
||||
@echo "📋 Доступные команды:"
|
||||
@echo "🤖 Quiz Bot - Команды управления"
|
||||
@echo "=================================="
|
||||
@echo ""
|
||||
@echo "📋 Development:"
|
||||
@echo " make install - Установить зависимости"
|
||||
@echo " make init - Инициализировать проект"
|
||||
@echo " make demo - Демонстрация возможностей"
|
||||
@echo " make test - Интерактивный тест"
|
||||
@echo " make test-bot - Проверить импорты и конфигурацию"
|
||||
@echo " make run - Запустить бота"
|
||||
@echo " make check - Проверить готовность"
|
||||
@echo " make reload-questions - Перезагрузить вопросы"
|
||||
@echo " make backup - Создать backup БД"
|
||||
@echo " make clean - Очистить временные файлы"
|
||||
@echo " make install-dev - Установить dev зависимости"
|
||||
@echo " make init - Инициализировать проект"
|
||||
@echo " make demo - Демонстрация возможностей"
|
||||
@echo " make test - Интерактивный тест"
|
||||
@echo " make run - Запустить бота"
|
||||
@echo " make check - Проверить готовность"
|
||||
@echo " make backup - Создать backup БД"
|
||||
@echo ""
|
||||
@echo "🐳 Docker:"
|
||||
@echo " make docker-build - Собрать Docker образ"
|
||||
@echo " make docker-dev - Запуск в Docker (dev)"
|
||||
@echo " make docker-test - Docker тесты"
|
||||
@echo " make docker-logs - Просмотр логов"
|
||||
@echo " make docker-deploy - Production деплой"
|
||||
@echo " make docker-monitor - Production мониторинг"
|
||||
@echo ""
|
||||
@echo "🔧 Code Quality:"
|
||||
@echo " make lint - Проверка кода"
|
||||
@echo " make format - Форматирование кода"
|
||||
@echo " make security - Проверка безопасности"
|
||||
@echo " make ci-test - Локальное CI тестирование"
|
||||
@echo ""
|
||||
@echo "🚀 Быстрый старт:"
|
||||
@echo " 1. make install"
|
||||
|
||||
48
docker-compose.prod.yml
Normal file
48
docker-compose.prod.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
quiz-bot:
|
||||
image: quiz-bot:${IMAGE_TAG:-latest}
|
||||
container_name: quiz-bot-prod
|
||||
restart: always
|
||||
environment:
|
||||
- BOT_TOKEN=${BOT_TOKEN}
|
||||
- DATABASE_PATH=data/quiz_bot.db
|
||||
- CSV_DATA_PATH=data/
|
||||
- LOG_LEVEL=INFO
|
||||
volumes:
|
||||
# Production data volumes
|
||||
- quiz-bot-data:/app/data
|
||||
- quiz-bot-logs:/app/logs
|
||||
networks:
|
||||
- quiz-bot-prod
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import sqlite3; conn = sqlite3.connect('/app/data/quiz_bot.db'); conn.close()"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 90s
|
||||
# Production resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 1G
|
||||
reservations:
|
||||
cpus: '0.2'
|
||||
memory: 256M
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
|
||||
networks:
|
||||
quiz-bot-prod:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
quiz-bot-data:
|
||||
driver: local
|
||||
quiz-bot-logs:
|
||||
driver: local
|
||||
55
docker-compose.yml
Normal file
55
docker-compose.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
quiz-bot:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: quiz-bot
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- BOT_TOKEN=${BOT_TOKEN}
|
||||
- DATABASE_PATH=data/quiz_bot.db
|
||||
- CSV_DATA_PATH=data/
|
||||
- LOG_LEVEL=INFO
|
||||
volumes:
|
||||
# Персистентное хранение данных
|
||||
- ./data:/app/data
|
||||
- ./logs:/app/logs
|
||||
networks:
|
||||
- quiz-bot-network
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import sqlite3; conn = sqlite3.connect('/app/data/quiz_bot.db'); conn.close()"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
# Ограничения ресурсов
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.1'
|
||||
memory: 128M
|
||||
|
||||
# Опциональный сервис для мониторинга логов
|
||||
log-viewer:
|
||||
image: goharbor/harbor-log:v2.5.0
|
||||
container_name: quiz-bot-logs
|
||||
profiles: ["monitoring"]
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./logs:/var/log/quiz-bot:ro
|
||||
networks:
|
||||
- quiz-bot-network
|
||||
|
||||
networks:
|
||||
quiz-bot-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
quiz-bot-data:
|
||||
driver: local
|
||||
147
scripts/deploy.sh
Executable file
147
scripts/deploy.sh
Executable file
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Скрипт для production деплоя
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
echo "🚀 Quiz Bot Production Deploy"
|
||||
echo "============================="
|
||||
|
||||
# Загрузка переменных окружения
|
||||
if [ -f "$PROJECT_ROOT/.env.prod" ]; then
|
||||
source "$PROJECT_ROOT/.env.prod"
|
||||
else
|
||||
echo "⚠️ Файл .env.prod не найден!"
|
||||
echo "📝 Создайте файл с production настройками"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверка обязательных переменных
|
||||
if [ -z "$BOT_TOKEN" ]; then
|
||||
echo "❌ BOT_TOKEN не установлен!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Функция для деплоя
|
||||
deploy_production() {
|
||||
echo "🔄 Деплой в production..."
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Создание backup базы данных если она существует
|
||||
if [ -f "data/quiz_bot.db" ]; then
|
||||
echo "💾 Создание backup базы данных..."
|
||||
cp data/quiz_bot.db "data/quiz_bot.db.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
fi
|
||||
|
||||
# Запуск production сервисов
|
||||
docker-compose -f docker-compose.prod.yml pull
|
||||
docker-compose -f docker-compose.prod.yml up -d --build
|
||||
|
||||
echo "⏳ Ожидание запуска сервисов..."
|
||||
sleep 30
|
||||
|
||||
# Проверка статуса
|
||||
echo "📋 Статус сервисов:"
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# Health check
|
||||
echo "🏥 Проверка health check..."
|
||||
if docker-compose -f docker-compose.prod.yml exec -T quiz-bot python -c "import sqlite3; conn = sqlite3.connect('/app/data/quiz_bot.db'); conn.close(); print('✅ Database OK')"; then
|
||||
echo "✅ Production деплой успешен!"
|
||||
else
|
||||
echo "❌ Health check не прошёл!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Функция для отката
|
||||
rollback() {
|
||||
echo "🔄 Откат к предыдущей версии..."
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Останавливаем текущие сервисы
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
|
||||
# Восстанавливаем backup базы данных
|
||||
LATEST_BACKUP=$(ls -t data/quiz_bot.db.backup.* 2>/dev/null | head -n1)
|
||||
if [ -n "$LATEST_BACKUP" ]; then
|
||||
echo "💾 Восстановление базы данных из $LATEST_BACKUP"
|
||||
cp "$LATEST_BACKUP" data/quiz_bot.db
|
||||
fi
|
||||
|
||||
# Запускаем с предыдущим образом
|
||||
export IMAGE_TAG=previous
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
echo "✅ Откат завершён"
|
||||
}
|
||||
|
||||
# Функция для мониторинга
|
||||
monitor() {
|
||||
echo "📊 Мониторинг production сервисов..."
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
while true; do
|
||||
clear
|
||||
echo "=== Quiz Bot Production Status ==="
|
||||
echo "Время: $(date)"
|
||||
echo ""
|
||||
|
||||
echo "📋 Статус контейнеров:"
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
echo ""
|
||||
|
||||
echo "💾 Использование ресурсов:"
|
||||
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
|
||||
echo ""
|
||||
|
||||
echo "📊 Логи (последние 10 строк):"
|
||||
docker-compose -f docker-compose.prod.yml logs --tail=10 quiz-bot
|
||||
echo ""
|
||||
|
||||
echo "Обновление через 30 сек... (Ctrl+C для выхода)"
|
||||
sleep 30
|
||||
done
|
||||
}
|
||||
|
||||
# Главное меню
|
||||
case "${1:-menu}" in
|
||||
"deploy")
|
||||
deploy_production
|
||||
;;
|
||||
"rollback")
|
||||
rollback
|
||||
;;
|
||||
"status")
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
;;
|
||||
"logs")
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
;;
|
||||
"monitor")
|
||||
monitor
|
||||
;;
|
||||
"stop")
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose -f docker-compose.prod.yml down
|
||||
echo "✅ Production сервисы остановлены"
|
||||
;;
|
||||
"menu"|*)
|
||||
echo ""
|
||||
echo "Использование: $0 [команда]"
|
||||
echo ""
|
||||
echo "Команды:"
|
||||
echo " deploy - Деплой в production"
|
||||
echo " rollback - Откат к предыдущей версии"
|
||||
echo " status - Статус сервисов"
|
||||
echo " logs - Показать логи"
|
||||
echo " monitor - Мониторинг в реальном времени"
|
||||
echo " stop - Остановить сервисы"
|
||||
echo ""
|
||||
;;
|
||||
esac
|
||||
148
scripts/dev.sh
Executable file
148
scripts/dev.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Скрипт для локальной разработки с Docker
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
echo "🐳 Quiz Bot Development Script"
|
||||
echo "=============================="
|
||||
|
||||
# Функция для проверки Docker
|
||||
check_docker() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "❌ Docker не установлен!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker info &> /dev/null; then
|
||||
echo "❌ Docker daemon не запущен!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Docker готов к работе"
|
||||
}
|
||||
|
||||
# Функция для сборки образа
|
||||
build_image() {
|
||||
echo "🔨 Сборка Docker образа..."
|
||||
cd "$PROJECT_ROOT"
|
||||
docker build -t quiz-bot:dev .
|
||||
echo "✅ Образ собран: quiz-bot:dev"
|
||||
}
|
||||
|
||||
# Функция для запуска в development режиме
|
||||
run_dev() {
|
||||
echo "🚀 Запуск в режиме разработки..."
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Проверяем .env файл
|
||||
if [ ! -f .env ]; then
|
||||
echo "⚠️ Файл .env не найден. Создаём шаблон..."
|
||||
cat > .env << EOF
|
||||
BOT_TOKEN=your_bot_token_here
|
||||
DATABASE_PATH=data/quiz_bot.db
|
||||
CSV_DATA_PATH=data/
|
||||
LOG_LEVEL=DEBUG
|
||||
EOF
|
||||
echo "📝 Заполните .env файл и запустите скрипт снова"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Создаём директории если их нет
|
||||
mkdir -p data logs
|
||||
|
||||
docker-compose up --build
|
||||
}
|
||||
|
||||
# Функция для остановки
|
||||
stop_dev() {
|
||||
echo "🛑 Остановка сервисов..."
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose down
|
||||
echo "✅ Сервисы остановлены"
|
||||
}
|
||||
|
||||
# Функция для очистки
|
||||
cleanup() {
|
||||
echo "🧹 Очистка Docker ресурсов..."
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose down --volumes --remove-orphans
|
||||
docker image rm quiz-bot:dev 2>/dev/null || true
|
||||
docker system prune -f
|
||||
echo "✅ Очистка завершена"
|
||||
}
|
||||
|
||||
# Функция для тестирования
|
||||
test_app() {
|
||||
echo "🧪 Запуск тестов..."
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Сборка тестового образа
|
||||
docker build -t quiz-bot:test .
|
||||
|
||||
# Запуск тестов в контейнере
|
||||
docker run --rm \
|
||||
-e BOT_TOKEN=test_token \
|
||||
-e DATABASE_PATH=":memory:" \
|
||||
quiz-bot:test \
|
||||
python -m pytest test_*.py -v
|
||||
|
||||
echo "✅ Тесты завершены"
|
||||
}
|
||||
|
||||
# Функция для логов
|
||||
show_logs() {
|
||||
echo "📋 Показ логов..."
|
||||
cd "$PROJECT_ROOT"
|
||||
docker-compose logs -f quiz-bot
|
||||
}
|
||||
|
||||
# Главное меню
|
||||
case "${1:-menu}" in
|
||||
"build")
|
||||
check_docker
|
||||
build_image
|
||||
;;
|
||||
"run"|"start")
|
||||
check_docker
|
||||
run_dev
|
||||
;;
|
||||
"stop")
|
||||
check_docker
|
||||
stop_dev
|
||||
;;
|
||||
"restart")
|
||||
check_docker
|
||||
stop_dev
|
||||
run_dev
|
||||
;;
|
||||
"test")
|
||||
check_docker
|
||||
test_app
|
||||
;;
|
||||
"logs")
|
||||
check_docker
|
||||
show_logs
|
||||
;;
|
||||
"cleanup")
|
||||
check_docker
|
||||
cleanup
|
||||
;;
|
||||
"menu"|*)
|
||||
echo ""
|
||||
echo "Использование: $0 [команда]"
|
||||
echo ""
|
||||
echo "Команды:"
|
||||
echo " build - Собрать Docker образ"
|
||||
echo " run - Запустить в режиме разработки"
|
||||
echo " stop - Остановить сервисы"
|
||||
echo " restart - Перезапустить сервисы"
|
||||
echo " test - Запустить тесты"
|
||||
echo " logs - Показать логи"
|
||||
echo " cleanup - Очистить Docker ресурсы"
|
||||
echo ""
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user