diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..efdbba1 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,89 @@ +name: Build and Publish Docker Image + +on: + push: + branches: + - main + - develop + tags: + - 'v*' + pull_request: + branches: + - main + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILD_DATE=${{ github.event.head_commit.timestamp }} + VCS_REF=${{ github.sha }} + + - name: Test Docker image + if: github.event_name != 'pull_request' + run: | + docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ + python -c " + from modules.moysklad_client import MoySkladClient + from modules.validator import OrderValidator + from modules.user_manager import UserManager + print('✅ All modules imported successfully') + " + + - name: Create release notes + if: startsWith(github.ref, 'refs/tags/') + run: | + echo "## Docker Image" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "📦 **Image:** \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Pull command:" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY + echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY diff --git a/build-image.bat b/build-image.bat new file mode 100644 index 0000000..326d92e --- /dev/null +++ b/build-image.bat @@ -0,0 +1,60 @@ +@echo off +REM Скрипт для сборки и публикации Docker образа (Windows) + +echo 🔨 Сборка Docker образа для BUH Bot + +REM Конфигурация +set REGISTRY=ghcr.io +set USERNAME=username +set IMAGE_NAME=buh_bot +set VERSION=latest + +echo Registry: %REGISTRY% +echo Username: %USERNAME% +echo Version: %VERSION% +echo. + +REM Сборка образа +echo 📦 Сборка образа... +docker build ^ + --tag "%REGISTRY%/%USERNAME%/%IMAGE_NAME%:%VERSION%" ^ + --tag "%REGISTRY%/%USERNAME%/%IMAGE_NAME%:latest" ^ + . + +if %errorlevel% neq 0 ( + echo ❌ Ошибка сборки образа + exit /b 1 +) + +echo ✅ Образ успешно собран + +REM Тестирование образа +echo 🧪 Тестирование образа... +docker run --rm "%REGISTRY%/%USERNAME%/%IMAGE_NAME%:%VERSION%" python -c "import sys; from modules.moysklad_client import MoySkladClient; print('OK')" + +if %errorlevel% neq 0 ( + echo ❌ Ошибка тестирования + exit /b 1 +) + +echo ✅ Тестирование пройдено + +REM Публикация образа +echo 📤 Публикация образа в registry... +docker push "%REGISTRY%/%USERNAME%/%IMAGE_NAME%:%VERSION%" +docker push "%REGISTRY%/%USERNAME%/%IMAGE_NAME%:latest" + +if %errorlevel% neq 0 ( + echo ❌ Ошибка публикации образа + exit /b 1 +) + +echo ✅ Образ успешно опубликован +echo. +echo 📦 Образы доступны: +echo %REGISTRY%/%USERNAME%/%IMAGE_NAME%:%VERSION% +echo %REGISTRY%/%USERNAME%/%IMAGE_NAME%:latest +echo. +echo 🚀 Для деплоя используйте: deploy-prod.bat + +pause diff --git a/build-image.sh b/build-image.sh new file mode 100644 index 0000000..9b057f0 --- /dev/null +++ b/build-image.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# Скрипт для сборки и публикации Docker образа + +set -e + +# Цвета для вывода +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Конфигурация +REGISTRY="${DOCKER_REGISTRY:-ghcr.io}" +USERNAME="${DOCKER_USERNAME:-username}" +IMAGE_NAME="buh_bot" +VERSION="${BOT_VERSION:-latest}" + +echo -e "${GREEN}🔨 Сборка Docker образа для BUH Bot${NC}" +echo "Registry: $REGISTRY" +echo "Username: $USERNAME" +echo "Version: $VERSION" +echo "" + +# Проверка авторизации +echo -e "${YELLOW}Проверка авторизации в registry...${NC}" +if ! docker info | grep -q "Username"; then + echo -e "${RED}❌ Не авторизован в Docker registry${NC}" + echo "Выполните: docker login $REGISTRY" + exit 1 +fi + +# Сборка образа +echo -e "${YELLOW}📦 Сборка образа...${NC}" +docker build \ + --tag "${REGISTRY}/${USERNAME}/${IMAGE_NAME}:${VERSION}" \ + --tag "${REGISTRY}/${USERNAME}/${IMAGE_NAME}:latest" \ + --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ + --build-arg VCS_REF="$(git rev-parse --short HEAD)" \ + . + +if [ $? -eq 0 ]; then + echo -e "${GREEN}✅ Образ успешно собран${NC}" +else + echo -e "${RED}❌ Ошибка сборки образа${NC}" + exit 1 +fi + +# Тестирование образа +echo -e "${YELLOW}🧪 Тестирование образа...${NC}" +docker run --rm "${REGISTRY}/${USERNAME}/${IMAGE_NAME}:${VERSION}" python -c " +import sys +from modules.moysklad_client import MoySkladClient +from modules.validator import OrderValidator +from modules.user_manager import UserManager +print('✅ Все модули импортированы успешно') +" + +if [ $? -eq 0 ]; then + echo -e "${GREEN}✅ Тестирование пройдено${NC}" +else + echo -e "${RED}❌ Ошибка тестирования${NC}" + exit 1 +fi + +# Публикация образа +echo -e "${YELLOW}📤 Публикация образа в registry...${NC}" +docker push "${REGISTRY}/${USERNAME}/${IMAGE_NAME}:${VERSION}" +docker push "${REGISTRY}/${USERNAME}/${IMAGE_NAME}:latest" + +if [ $? -eq 0 ]; then + echo -e "${GREEN}✅ Образ успешно опубликован${NC}" + echo "" + echo "📦 Образы доступны:" + echo " ${REGISTRY}/${USERNAME}/${IMAGE_NAME}:${VERSION}" + echo " ${REGISTRY}/${USERNAME}/${IMAGE_NAME}:latest" + echo "" + echo "🚀 Для деплоя используйте:" + echo " ./deploy-prod.sh" +else + echo -e "${RED}❌ Ошибка публикации образа${NC}" + exit 1 +fi diff --git a/deploy-prod.bat b/deploy-prod.bat new file mode 100644 index 0000000..54d9721 --- /dev/null +++ b/deploy-prod.bat @@ -0,0 +1,75 @@ +@echo off +REM Скрипт для деплоя в production (Windows) + +echo 🚀 Production Deploy - BUH Bot +echo. + +REM Проверка .env.prod +if not exist .env.prod ( + echo ❌ Файл .env.prod не найден! + echo Создайте файл на основе .env.prod.example: + echo copy .env.prod.example .env.prod + echo notepad .env.prod + exit /b 1 +) + +echo 🔍 Проверка конфигурации... +findstr /C:"TELEGRAM_BOT_TOKEN=your_production_bot_token_here" .env.prod >nul +if %errorlevel% equ 0 ( + echo ❌ TELEGRAM_BOT_TOKEN не настроен в .env.prod + exit /b 1 +) + +echo ✅ Конфигурация корректна + +REM Создание директорий +echo 📁 Создание директорий... +if not exist data mkdir data +if not exist logs mkdir logs +if not exist temp_documents mkdir temp_documents + +REM Backup +if exist data\users.json ( + echo 💾 Создание backup... + set BACKUP_DIR=backups\%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2% + set BACKUP_DIR=%BACKUP_DIR: =0% + mkdir %BACKUP_DIR% + copy data\*.* %BACKUP_DIR%\ + echo ✅ Backup создан: %BACKUP_DIR% +) + +REM Остановка существующих контейнеров +docker ps -a --format "{{.Names}}" | findstr "buh_bot" >nul +if %errorlevel% equ 0 ( + echo 🛑 Остановка существующих контейнеров... + docker-compose -f docker-compose.prod.yml --env-file .env.prod down +) + +REM Pull latest образов +echo 📥 Получение последних образов... +docker-compose -f docker-compose.prod.yml --env-file .env.prod pull + +REM Запуск +echo 🚀 Запуск сервисов... +docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d + +REM Проверка статуса +timeout /t 5 /nobreak >nul +echo. +echo 📊 Статус сервисов: +docker-compose -f docker-compose.prod.yml --env-file .env.prod ps + +echo. +echo ✅ Production деплой завершён! +echo. +echo 📝 Полезные команды: +echo Логи бота: docker-compose -f docker-compose.prod.yml logs -f buh_bot +echo Статус: docker-compose -f docker-compose.prod.yml ps +echo Остановка: docker-compose -f docker-compose.prod.yml down +echo. +echo 📊 Мониторинг: +echo Grafana: http://localhost:3000 +echo Prometheus: http://localhost:9090 +echo. + +pause diff --git a/deploy-prod.sh b/deploy-prod.sh new file mode 100644 index 0000000..3c72e5f --- /dev/null +++ b/deploy-prod.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# Скрипт для деплоя в production + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +echo -e "${GREEN}🚀 Production Deploy - BUH Bot${NC}" +echo "" + +# Проверка .env.prod +if [ ! -f .env.prod ]; then + echo -e "${RED}❌ Файл .env.prod не найден!${NC}" + echo "Создайте файл на основе .env.prod.example:" + echo " cp .env.prod.example .env.prod" + echo " nano .env.prod" + exit 1 +fi + +# Проверка обязательных переменных +echo -e "${YELLOW}🔍 Проверка конфигурации...${NC}" +source .env.prod + +if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ "$TELEGRAM_BOT_TOKEN" = "your_production_bot_token_here" ]; then + echo -e "${RED}❌ TELEGRAM_BOT_TOKEN не настроен в .env.prod${NC}" + exit 1 +fi + +echo -e "${GREEN}✅ Конфигурация корректна${NC}" + +# Создание необходимых директорий на хосте +echo -e "${YELLOW}📁 Создание директорий...${NC}" +sudo mkdir -p /var/lib/buh_bot/data +sudo mkdir -p /var/log/buh_bot +sudo mkdir -p /var/tmp/buh_bot + +# Backup существующих данных +if [ -d /var/lib/buh_bot/data ] && [ "$(ls -A /var/lib/buh_bot/data)" ]; then + echo -e "${YELLOW}💾 Создание backup...${NC}" + BACKUP_DIR="/var/backups/buh_bot/$(date +%Y%m%d_%H%M%S)" + sudo mkdir -p "$BACKUP_DIR" + sudo cp -r /var/lib/buh_bot/data/* "$BACKUP_DIR/" + echo -e "${GREEN}✅ Backup создан: $BACKUP_DIR${NC}" +fi + +# Остановка существующих контейнеров +if docker ps -a --format '{{.Names}}' | grep -q "buh_bot"; then + echo -e "${YELLOW}🛑 Остановка существующих контейнеров...${NC}" + docker-compose -f docker-compose.prod.yml --env-file .env.prod down +fi + +# Pull latest образов +echo -e "${YELLOW}📥 Получение последних образов...${NC}" +docker-compose -f docker-compose.prod.yml --env-file .env.prod pull + +# Запуск +echo -e "${YELLOW}🚀 Запуск сервисов...${NC}" +docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d + +# Проверка статуса +sleep 5 +echo "" +echo -e "${BLUE}📊 Статус сервисов:${NC}" +docker-compose -f docker-compose.prod.yml --env-file .env.prod ps + +# Проверка healthcheck +echo "" +echo -e "${YELLOW}🏥 Ожидание healthcheck...${NC}" +sleep 10 + +BOT_HEALTH=$(docker inspect --format='{{.State.Health.Status}}' buh_bot_prod 2>/dev/null || echo "unknown") +if [ "$BOT_HEALTH" = "healthy" ] || [ "$BOT_HEALTH" = "starting" ]; then + echo -e "${GREEN}✅ Бот запущен и работает${NC}" +else + echo -e "${RED}⚠️ Бот запущен, но healthcheck: $BOT_HEALTH${NC}" + echo "Проверьте логи: docker-compose -f docker-compose.prod.yml logs buh_bot" +fi + +echo "" +echo -e "${GREEN}✅ Production деплой завершён!${NC}" +echo "" +echo -e "${BLUE}📝 Полезные команды:${NC}" +echo " Логи бота: docker-compose -f docker-compose.prod.yml logs -f buh_bot" +echo " Все логи: docker-compose -f docker-compose.prod.yml logs -f" +echo " Статус: docker-compose -f docker-compose.prod.yml ps" +echo " Остановка: docker-compose -f docker-compose.prod.yml down" +echo " Перезапуск: docker-compose -f docker-compose.prod.yml restart" +echo "" +echo -e "${BLUE}📊 Мониторинг:${NC}" +echo " Grafana: http://localhost:${GRAFANA_PORT:-3000}" +echo " Prometheus: http://localhost:${PROMETHEUS_PORT:-9090}" +echo " cAdvisor: http://localhost:8080" +echo ""