feat: Add CI/CD pipeline and deployment automation
GitHub Actions Workflow: - Automatic build on push to main/develop - Build on tags (v*.*.*) - Multi-platform support (linux/amd64) - Publish to ghcr.io registry - Docker layer caching - Metadata extraction for tags Build Scripts (Linux + Windows): - build-image.sh/bat: Build and publish to registry - Registry authentication check - Image testing before push - Configurable registry (default: ghcr.io) Deployment Scripts (Linux + Windows): - deploy-prod.sh/bat: Production deployment automation - Pre-deployment checks (.env.prod validation) - Automatic backup before deploy - Image pull and stack deployment - Health check verification - Rollback support
This commit is contained in:
parent
4800e8c375
commit
b7853637bc
89
.github/workflows/docker-build.yml
vendored
Normal file
89
.github/workflows/docker-build.yml
vendored
Normal file
@ -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
|
||||
60
build-image.bat
Normal file
60
build-image.bat
Normal file
@ -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
|
||||
82
build-image.sh
Normal file
82
build-image.sh
Normal file
@ -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
|
||||
75
deploy-prod.bat
Normal file
75
deploy-prod.bat
Normal file
@ -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
|
||||
97
deploy-prod.sh
Normal file
97
deploy-prod.sh
Normal file
@ -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 ""
|
||||
Loading…
x
Reference in New Issue
Block a user