diff --git a/.env.testing.example b/.env.testing.example new file mode 100644 index 0000000..8df2c2e --- /dev/null +++ b/.env.testing.example @@ -0,0 +1,64 @@ +# Environment Variables for Testing Deployments + +# Copy this file to .env in your deployment directory + +# ================================ +# APPLICATION SETTINGS +# ================================ +NODE_ENV=testing +APP_PORT=3123 # Will be dynamically set to 3000 + PR_NUMBER + +# ================================ +# DATABASE CONFIGURATION +# ================================ +DB_HOST=mariadb +DB_PORT=3306 +DB_DATABASE=low_code_engine_pr_123 # Will be dynamically set +DB_USERNAME=app_user +DB_PASSWORD=your_strong_password_here +DB_ROOT_PASSWORD=your_strong_root_password_here + +# ================================ +# REDIS CONFIGURATION +# ================================ +REDIS_HOST=redis +REDIS_PORT=6379 + +# ================================ +# API TOKENS (if needed) +# ================================ +# API_TOKEN_SECRET=your_api_token_secret +# ADMIN_TOKEN=your_admin_token + +# ================================ +# EXTERNAL SERVICES (if any) +# ================================ +# EXTERNAL_API_URL=https://api.example.com +# EXTERNAL_API_KEY=your_external_api_key + +# ================================ +# LOGGING & MONITORING +# ================================ +LOG_LEVEL=debug +# SENTRY_DSN=https://your-sentry-dsn@sentry.io/project-id + +# ================================ +# PERFORMANCE SETTINGS +# ================================ +# MAX_CONNECTIONS=100 +# TIMEOUT=30000 + +# ================================ +# FEATURE FLAGS (if any) +# ================================ +# ENABLE_FEATURE_X=true +# ENABLE_DEBUG_MODE=true + +# ================================ +# NOTES FOR DEPLOYMENT +# ================================ +# - This file is automatically generated by GitHub Actions +# - PR_NUMBER will be substituted with actual PR number +# - Ports will be calculated as BASE_PORT + PR_NUMBER +# - Database name will include PR number for isolation +# - Do not commit this file with real secrets! \ No newline at end of file diff --git a/.gitea/workflows/deploy-testing.yml b/.gitea/workflows/deploy-testing.yml new file mode 100644 index 0000000..1c6e0e3 --- /dev/null +++ b/.gitea/workflows/deploy-testing.yml @@ -0,0 +1,247 @@ +name: Deploy to Testing Server + +on: + pull_request: + branches: + - develop + types: [opened, synchronize, reopened] + +jobs: + deploy: + name: Deploy to Testing Server + runs-on: ubuntu-latest + if: github.event.pull_request.merged == false # Только для открытых PR + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "18" + cache: "yarn" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run linting + run: yarn lint:check + + - name: Build application + run: yarn build + + - name: Build Docker image + run: | + docker build -t low-code-engine:testing-${{ github.event.pull_request.number }} . + + - name: Save Docker image + run: | + docker save low-code-engine:testing-${{ github.event.pull_request.number }} | gzip > low-code-engine-testing.tar.gz + + - name: Deploy to Testing Server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + # Создаем директорию для приложения если её нет + mkdir -p /opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }} + cd /opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }} + + # Останавливаем существующие контейнеры если они есть + docker-compose down || true + + # Удаляем старые образы + docker image prune -f || true + + - name: Copy files to server + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + source: "low-code-engine-testing.tar.gz,docker-compose.yml,docker/" + target: "/opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }}/" + + - name: Load and run Docker containers + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + cd /opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }} + + # Загружаем Docker образ + gunzip -c low-code-engine-testing.tar.gz | docker load + + # Создаем .env файл для тестового окружения + cat > .env << EOF + NODE_ENV=testing + DB_ROOT_PASSWORD=${{ secrets.TESTING_DB_ROOT_PASSWORD }} + DB_DATABASE=low_code_engine_pr_${{ github.event.pull_request.number }} + DB_USERNAME=${{ secrets.TESTING_DB_USERNAME }} + DB_PASSWORD=${{ secrets.TESTING_DB_PASSWORD }} + DB_PORT=3306 + APP_PORT=${{ vars.TESTING_BASE_PORT || 3000 }}${{ github.event.pull_request.number }} + REDIS_HOST=redis + REDIS_PORT=6379 + EOF + + # Создаем docker-compose.override.yml для тестового окружения + cat > docker-compose.override.yml << EOF + version: "3.8" + services: + app: + image: low-code-engine:testing-${{ github.event.pull_request.number }} + ports: + - "\${APP_PORT}:3000" + environment: + NODE_ENV: testing + DB_HOST: mariadb + DB_PORT: 3306 + DB_USERNAME: \${DB_USERNAME} + DB_PASSWORD: \${DB_PASSWORD} + DB_DATABASE: \${DB_DATABASE} + REDIS_HOST: redis + REDIS_PORT: 6379 + + mariadb: + ports: + - "${{ vars.TESTING_BASE_DB_PORT || 3306 }}${{ github.event.pull_request.number }}:3306" + environment: + MYSQL_DATABASE: \${DB_DATABASE} + + redis: + image: redis:7-alpine + ports: + - "${{ vars.TESTING_BASE_REDIS_PORT || 6379 }}${{ github.event.pull_request.number }}:6379" + EOF + + # Запускаем контейнеры + docker-compose up -d + + # Ждем пока база данных запустится + sleep 30 + + # Запускаем миграции + docker-compose exec -T app yarn migration:run || true + + # Проверяем статус контейнеров + docker-compose ps + + - name: Health check + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + cd /opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }} + + # Проверяем доступность приложения + APP_PORT=${{ vars.TESTING_BASE_PORT || 3000 }}${{ github.event.pull_request.number }} + + for i in {1..10}; do + if curl -f http://localhost:$APP_PORT/health > /dev/null 2>&1; then + echo "✅ Application is healthy on port $APP_PORT" + break + fi + echo "⏳ Waiting for application to start... (attempt $i/10)" + sleep 10 + done + + - name: Comment PR with deployment info + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const appPort = ${{ vars.TESTING_BASE_PORT || 3000 }} + prNumber; + const dbPort = ${{ vars.TESTING_BASE_DB_PORT || 3306 }} + prNumber; + const redisPort = ${{ vars.TESTING_BASE_REDIS_PORT || 6379 }} + prNumber; + + const comment = `## 🚀 Testing Deployment + + Your PR has been deployed to the testing server! + + **Deployment Details:** + - 🌐 Application URL: http://${{ secrets.TESTING_SERVER_HOST }}:${appPort} + - 🗄️ Database Port: ${dbPort} + - 🔴 Redis Port: ${redisPort} + - 📁 Server Path: \`/opt/low-code-engine/testing-pr-${prNumber}\` + + **Available Commands on Server:** + \`\`\`bash + cd /opt/low-code-engine/testing-pr-${prNumber} + docker-compose logs app # View application logs + docker-compose logs mariadb # View database logs + docker-compose ps # Check container status + docker-compose exec app yarn migration:run # Run migrations + \`\`\` + + > **Note:** This deployment will be automatically cleaned up when the PR is closed or merged. + `; + + github.rest.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + + cleanup: + name: Cleanup on PR Close + runs-on: ubuntu-latest + if: github.event.pull_request.state == 'closed' + + steps: + - name: Cleanup testing environment + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + cd /opt/low-code-engine/testing-pr-${{ github.event.pull_request.number }} + + # Останавливаем и удаляем контейнеры + docker-compose down -v || true + + # Удаляем Docker образ + docker rmi low-code-engine:testing-${{ github.event.pull_request.number }} || true + + # Удаляем директорию развертывания + cd .. + rm -rf testing-pr-${{ github.event.pull_request.number }} + + echo "✅ Cleanup completed for PR #${{ github.event.pull_request.number }}" + + - name: Comment PR with cleanup info + uses: actions/github-script@v7 + with: + script: | + const comment = `## 🧹 Testing Environment Cleaned Up + + The testing deployment for this PR has been cleaned up: + - ✅ Docker containers stopped and removed + - ✅ Docker images cleaned up + - ✅ Server files removed + + Thank you for testing! 🎉 + `; + + github.rest.issues.createComment({ + issue_number: context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); diff --git a/.gitea/workflows/test-deployment.yml b/.gitea/workflows/test-deployment.yml new file mode 100644 index 0000000..d1c6032 --- /dev/null +++ b/.gitea/workflows/test-deployment.yml @@ -0,0 +1,237 @@ +name: Test Deployment Workflow + +# Этот workflow можно запустить вручную для тестирования процесса развертывания +on: + workflow_dispatch: + inputs: + pr_number: + description: "PR number to simulate" + required: true + default: "999" + type: string + cleanup: + description: "Run cleanup after deployment" + required: false + default: false + type: boolean + +jobs: + test-deployment: + name: Test Deployment Process + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "18" + cache: "yarn" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Run tests + run: | + # Add your test commands here + echo "Running tests..." + yarn lint:check || echo "Linting completed with warnings" + + - name: Build application + run: yarn build + + - name: Build Docker image + run: | + docker build -t low-code-engine:test-${{ inputs.pr_number }} . + echo "Docker image built successfully" + + - name: Test Docker image + run: | + # Test that the image runs correctly + docker run -d --name test-app -p 3000:3000 low-code-engine:test-${{ inputs.pr_number }} + sleep 10 + + # Try to connect to the app + if curl -f http://localhost:3000/health > /dev/null 2>&1; then + echo "✅ Application is responding" + else + echo "❌ Application is not responding" + docker logs test-app + fi + + docker stop test-app + docker rm test-app + + - name: Save Docker image + run: | + docker save low-code-engine:test-${{ inputs.pr_number }} | gzip > low-code-engine-test.tar.gz + ls -lh low-code-engine-test.tar.gz + + - name: Test SSH connection + if: ${{ secrets.TESTING_SERVER_HOST }} + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + echo "✅ SSH connection successful" + echo "Server info:" + uname -a + docker --version + docker-compose --version + df -h /opt/low-code-engine + echo "Available ports for testing:" + netstat -tln | grep ":30[0-9][0-9]" | head -5 || echo "No testing ports in use" + + - name: Test file transfer + if: ${{ secrets.TESTING_SERVER_HOST }} + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + source: "low-code-engine-test.tar.gz" + target: "/tmp/" + + - name: Test deployment simulation + if: ${{ secrets.TESTING_SERVER_HOST }} + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + echo "Testing deployment simulation for PR #${{ inputs.pr_number }}" + + # Create test directory + mkdir -p /opt/low-code-engine/test-pr-${{ inputs.pr_number }} + cd /opt/low-code-engine/test-pr-${{ inputs.pr_number }} + + # Copy test file + cp /tmp/low-code-engine-test.tar.gz . + + # Test image loading + gunzip -c low-code-engine-test.tar.gz | docker load + + echo "✅ Test deployment simulation completed" + + # Cleanup test files + rm -f low-code-engine-test.tar.gz /tmp/low-code-engine-test.tar.gz + docker rmi low-code-engine:test-${{ inputs.pr_number }} || true + cd .. + rm -rf test-pr-${{ inputs.pr_number }} + + - name: Cleanup on failure + if: failure() && secrets.TESTING_SERVER_HOST + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + # Cleanup any test artifacts + rm -f /tmp/low-code-engine-test.tar.gz + rm -rf /opt/low-code-engine/test-pr-${{ inputs.pr_number }} + docker rmi low-code-engine:test-${{ inputs.pr_number }} || true + echo "🧹 Cleanup completed" + + test-health-endpoints: + name: Test Health Endpoints + runs-on: ubuntu-latest + needs: test-deployment + if: ${{ secrets.TESTING_SERVER_HOST }} + + steps: + - name: Test server health endpoints + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.TESTING_SERVER_HOST }} + username: ${{ secrets.TESTING_SERVER_USER }} + key: ${{ secrets.TESTING_SERVER_SSH_KEY }} + port: ${{ secrets.TESTING_SERVER_PORT || 22 }} + script: | + echo "Testing health check endpoints..." + + # Test monitoring script + if [ -f /usr/local/bin/monitor-deployments ]; then + echo "✅ Monitor script exists" + /usr/local/bin/monitor-deployments | head -20 + else + echo "❌ Monitor script not found" + fi + + # Test cleanup script + if [ -f /usr/local/bin/cleanup-old-deployments ]; then + echo "✅ Cleanup script exists" + else + echo "❌ Cleanup script not found" + fi + + # Test nginx configuration + if command -v nginx &> /dev/null; then + echo "✅ Nginx is installed" + nginx -t 2>&1 | head -5 + else + echo "❌ Nginx not installed" + fi + + # Test docker access + docker ps | head -5 + echo "Docker system info:" + docker system df + + security-check: + name: Security Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run security audit + run: | + echo "Running security checks..." + + # Check for secrets in code + if grep -r "password\|secret\|key" --include="*.ts" --include="*.js" --include="*.json" src/ | grep -v "// TODO\|console.log"; then + echo "❌ Potential secrets found in code" + exit 1 + else + echo "✅ No secrets found in source code" + fi + + # Check Docker image for security issues + echo "Building secure Docker image..." + docker build -t security-test . + + # Basic security checks + echo "Checking Docker image user..." + docker run --rm security-test whoami | grep -v root || echo "✅ Not running as root" + + docker rmi security-test + + - name: Check workflow security + run: | + echo "Checking workflow file security..." + + # Check that secrets are properly referenced + if grep -E '\$\{\{\s*secrets\.' .github/workflows/*.yml > /dev/null; then + echo "✅ Secrets properly referenced" + else + echo "❌ No secrets found in workflows" + fi + + # Check for hardcoded values + if grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' .github/workflows/*.yml; then + echo "❌ Hardcoded IP addresses found" + exit 1 + else + echo "✅ No hardcoded IP addresses" + fi diff --git a/DEPLOYMENT-README.md b/DEPLOYMENT-README.md new file mode 100644 index 0000000..5d30bec --- /dev/null +++ b/DEPLOYMENT-README.md @@ -0,0 +1,238 @@ +# 🚀 Автоматическое развертывание на тестовом сервере + +## Обзор + +Этот репозиторий содержит GitHub Actions workflow для автоматического развертывания приложения на тестовом сервере при создании Pull Request в ветку `develop`. Каждый PR получает свою изолированную среду тестирования. + +## 📁 Структура файлов + +``` +.github/workflows/ +├── deploy-testing.yml # Основной workflow для развертывания +└── test-deployment.yml # Workflow для тестирования развертывания + +scripts/ +└── setup-testing-server.sh # Скрипт настройки тестового сервера + +DEPLOYMENT.md # Подробная документация по настройке +QUICK-START.md # Быстрый старт +.env.testing.example # Пример переменных окружения +``` + +## ⚡ Быстрый старт + +### 1. Настройте тестовый сервер + +```bash +# На вашем тестовом сервере выполните: +curl -sSL https://raw.githubusercontent.com/YOUR_USERNAME/YOUR_REPO/main/scripts/setup-testing-server.sh | bash +``` + +### 2. Добавьте GitHub Secrets + +В настройках репозитория добавьте следующие секреты: + +``` +TESTING_SERVER_HOST=your.server.ip.address +TESTING_SERVER_USER=deploy +TESTING_SERVER_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY----- +your private SSH key content +-----END OPENSSH PRIVATE KEY----- +TESTING_DB_ROOT_PASSWORD=strong_root_password +TESTING_DB_USERNAME=app_user +TESTING_DB_PASSWORD=strong_user_password +``` + +### 3. Создайте Pull Request + +1. Создайте новую ветку от `develop` +2. Внесите изменения +3. Создайте Pull Request в ветку `develop` +4. GitHub Actions автоматически развернет ваше приложение +5. Проверьте комментарий в PR с ссылкой на развертывание + +## 🏗️ Как это работает + +### Workflow процесс + +1. **Триггер**: Pull Request в ветку `develop` +2. **Сборка**: Установка зависимостей, линтинг, сборка приложения +3. **Docker**: Создание Docker образа +4. **Развертывание**: Копирование файлов на сервер и запуск контейнеров +5. **Проверка**: Health check и уведомление в PR +6. **Очистка**: Автоматическая очистка при закрытии PR + +### Архитектура развертывания + +``` +Тестовый сервер +├── /opt/low-code-engine/ +│ ├── testing-pr-123/ # Изолированная среда для PR #123 +│ │ ├── docker-compose.yml +│ │ ├── docker-compose.override.yml +│ │ ├── .env +│ │ └── docker/ +│ ├── testing-pr-124/ # Изолированная среда для PR #124 +│ └── ... +└── Порты: + ├── Приложение: 3000 + PR_NUMBER + ├── База данных: 3300 + PR_NUMBER + └── Redis: 6300 + PR_NUMBER +``` + +## 🔧 Конфигурация + +### Порты по умолчанию + +- **Приложение**: 3000 + номер PR (например, PR #123 → порт 3123) +- **База данных**: 3300 + номер PR (например, PR #123 → порт 3423) +- **Redis**: 6300 + номер PR (например, PR #123 → порт 6423) + +### Переменные окружения + +Можно настроить базовые порты через GitHub Variables: + +``` +TESTING_BASE_PORT=3000 # Базовый порт приложения +TESTING_BASE_DB_PORT=3300 # Базовый порт БД +TESTING_BASE_REDIS_PORT=6300 # Базовый порт Redis +``` + +## 📊 Мониторинг + +### Команды на сервере + +```bash +# Мониторинг всех развертываний +sudo /usr/local/bin/monitor-deployments + +# Очистка старых развертываний (старше 7 дней) +sudo /usr/local/bin/cleanup-old-deployments + +# Просмотр логов конкретного PR +cd /opt/low-code-engine/testing-pr-123 +docker-compose logs -f app + +# Проверка статуса +docker-compose ps +``` + +### Пример вывода мониторинга + +``` +=== Testing Deployments Status === +Date: Mon Oct 13 10:30:00 UTC 2025 + +Active Deployments: + PR #123: Running on port 3123 + Status: ✅ Healthy + PR #124: Running on port 3124 + Status: ❌ Unhealthy + +=== System Resources === +Disk Usage: +/dev/sda1 20G 8.5G 11G 45% /opt/low-code-engine +``` + +## 🔒 Безопасность + +### Рекомендации + +1. **SSH ключи**: Используйте отдельный SSH ключ только для развертывания +2. **Пользователь**: Создайте отдельного пользователя `deploy` с минимальными правами +3. **Firewall**: Настройте фаервол для ограничения доступа +4. **Пароли**: Используйте сильные пароли для базы данных +5. **Автоочистка**: Включена автоматическая очистка старых развертываний + +### Настройка firewall + +```bash +sudo ufw enable +sudo ufw allow ssh +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +sudo ufw allow 3000:3999/tcp # Порты приложений +sudo ufw allow 3300:3999/tcp # Порты БД +sudo ufw allow 6300:6999/tcp # Порты Redis +``` + +## 🧪 Тестирование + +### Тестирование самого процесса развертывания + +Запустите тестовый workflow вручную: + +1. Перейдите в Actions → Test Deployment Workflow +2. Нажмите "Run workflow" +3. Укажите номер PR для симуляции (например, 999) +4. Запустите тест + +### Локальное тестирование + +```bash +# Сборка и тест Docker образа локально +docker build -t low-code-engine:local . +docker run -d --name test-app -p 3000:3000 low-code-engine:local + +# Проверка health endpoint +curl http://localhost:3000/health + +# Очистка +docker stop test-app && docker rm test-app +``` + +## 📚 Дополнительная документация + +- [DEPLOYMENT.md](./DEPLOYMENT.md) - Подробная документация по настройке +- [QUICK-START.md](./QUICK-START.md) - Краткое руководство по быстрому старту +- [.env.testing.example](./.env.testing.example) - Пример переменных окружения + +## 🛠️ Troubleshooting + +### Часто встречающиеся проблемы + +#### "Permission denied" при SSH + +```bash +# Проверьте права на сервере +sudo ls -la /home/deploy/.ssh/ +sudo chmod 700 /home/deploy/.ssh/ +sudo chmod 600 /home/deploy/.ssh/authorized_keys +``` + +#### Порт уже занят + +```bash +# Найдите процесс +sudo netstat -tulpn | grep :3123 + +# Остановите развертывание +cd /opt/low-code-engine/testing-pr-123 +docker-compose down +``` + +#### Нехватка места на диске + +```bash +# Очистка Docker +docker system prune -a -f + +# Очистка старых развертываний +sudo /usr/local/bin/cleanup-old-deployments +``` + +## 🤝 Вклад в развитие + +1. Создайте форк репозитория +2. Создайте ветку для новой функции +3. Внесите изменения +4. Создайте Pull Request +5. Протестируйте развертывание + +## 📝 Лицензия + +Этот проект использует лицензию, указанную в основном проекте. + +--- + +💡 **Совет**: Начните с [QUICK-START.md](./QUICK-START.md) для быстрой настройки, затем обратитесь к [DEPLOYMENT.md](./DEPLOYMENT.md) для подробной конфигурации. diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..8e5567b --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,209 @@ +# GitHub Actions Deployment Setup + +Этот документ описывает настройку автоматического развертывания на тестовом сервере при создании Pull Request в ветку `develop`. + +## Требуемые GitHub Secrets + +Перейдите в настройки репозитория → Settings → Secrets and variables → Actions и добавьте следующие секреты: + +### SSH Connection + +- `TESTING_SERVER_HOST` - IP адрес или домен тестового сервера +- `TESTING_SERVER_USER` - Пользователь для SSH подключения (например: `deploy`) +- `TESTING_SERVER_SSH_KEY` - Приватный SSH ключ для подключения к серверу +- `TESTING_SERVER_PORT` - (опционально) Порт SSH (по умолчанию 22) + +### Database Configuration + +- `TESTING_DB_ROOT_PASSWORD` - Root пароль для MariaDB +- `TESTING_DB_USERNAME` - Пользователь базы данных +- `TESTING_DB_PASSWORD` - Пароль пользователя базы данных + +## Требуемые GitHub Variables + +Перейдите в настройки репозитория → Settings → Secrets and variables → Actions → Variables и добавьте: + +- `TESTING_BASE_PORT` - Базовый порт для приложений (по умолчанию: 3000) +- `TESTING_BASE_DB_PORT` - Базовый порт для баз данных (по умолчанию: 3306) +- `TESTING_BASE_REDIS_PORT` - Базовый порт для Redis (по умолчанию: 6379) + +## Настройка тестового сервера + +### 1. Установка Docker и Docker Compose + +```bash +# Обновление системы +sudo apt update && sudo apt upgrade -y + +# Установка Docker +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh + +# Добавление пользователя в группу docker +sudo usermod -aG docker $USER + +# Установка Docker Compose +sudo apt install docker-compose-plugin -y +``` + +### 2. Создание пользователя для развертывания + +```bash +# Создание пользователя +sudo useradd -m -s /bin/bash deploy +sudo usermod -aG docker deploy + +# Создание директории для SSH ключей +sudo mkdir -p /home/deploy/.ssh +sudo chmod 700 /home/deploy/.ssh + +# Добавление публичного SSH ключа +sudo nano /home/deploy/.ssh/authorized_keys +# Вставьте публичный ключ, соответствующий приватному ключу в TESTING_SERVER_SSH_KEY + +sudo chmod 600 /home/deploy/.ssh/authorized_keys +sudo chown -R deploy:deploy /home/deploy/.ssh + +# Создание директории для приложений +sudo mkdir -p /opt/low-code-engine +sudo chown deploy:deploy /opt/low-code-engine +``` + +### 3. Настройка Nginx (опционально) + +Если хотите использовать доменные имена вместо портов: + +```bash +sudo apt install nginx -y + +# Создание конфигурации для тестовых приложений +sudo nano /etc/nginx/sites-available/testing-apps +``` + +Содержимое файла: + +```nginx +server { + listen 80; + server_name ~^pr-(?\d+)\.testing\.yourdomain\.com$; + + location / { + set $app_port 3000$pr_number; + proxy_pass http://127.0.0.1:$app_port; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +```bash +# Активация конфигурации +sudo ln -s /etc/nginx/sites-available/testing-apps /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx +``` + +## Как работает развертывание + +### Процесс развертывания + +1. **Trigger**: Создание или обновление Pull Request в ветку `develop` +2. **Build**: Сборка приложения и создание Docker образа +3. **Deploy**: Копирование файлов на сервер и запуск контейнеров +4. **Health Check**: Проверка доступности приложения +5. **Comment**: Добавление комментария в PR с информацией о развертывании + +### Структура на сервере + +``` +/opt/low-code-engine/ +├── testing-pr-123/ # Отдельная директория для каждого PR +│ ├── docker-compose.yml # Основной docker-compose файл +│ ├── docker-compose.override.yml # Переопределения для тестинга +│ ├── .env # Переменные окружения +│ ├── docker/ # Docker конфигурации +│ └── low-code-engine-testing.tar.gz # Docker образ +├── testing-pr-124/ +└── ... +``` + +### Порты + +Каждому PR назначаются уникальные порты: + +- Приложение: `TESTING_BASE_PORT + PR_NUMBER` (например: 3000 + 123 = 3123) +- База данных: `TESTING_BASE_DB_PORT + PR_NUMBER` (например: 3306 + 123 = 3429) +- Redis: `TESTING_BASE_REDIS_PORT + PR_NUMBER` (например: 6379 + 123 = 6502) + +### Cleanup + +При закрытии или мердже PR автоматически происходит: + +1. Остановка и удаление контейнеров +2. Удаление Docker образов +3. Удаление файлов на сервере +4. Добавление комментария об очистке + +## Безопасность + +1. **SSH ключи**: Используйте отдельный SSH ключ только для развертывания +2. **Пользователь**: Создайте отдельного пользователя с минимальными правами +3. **Firewall**: Настройте фаервол для ограничения доступа к портам +4. **SSL/TLS**: Рассмотрите использование SSL сертификатов для HTTPS + +## Мониторинг и логи + +### Просмотр логов приложения + +```bash +cd /opt/low-code-engine/testing-pr-{PR_NUMBER} +docker-compose logs -f app +``` + +### Просмотр статуса контейнеров + +```bash +docker-compose ps +``` + +### Мониторинг ресурсов + +```bash +docker stats +``` + +## Troubleshooting + +### Проблемы с портами + +Если порт занят, проверьте какие приложения его используют: + +```bash +sudo netstat -tulpn | grep :{PORT} +``` + +### Проблемы с Docker + +Очистка неиспользуемых ресурсов: + +```bash +docker system prune -f +``` + +### Проблемы с базой данных + +Проверка подключения к базе данных: + +```bash +docker-compose exec mariadb mysql -u root -p -e "SHOW DATABASES;" +``` + +### Проблемы с миграциями + +Ручной запуск миграций: + +```bash +docker-compose exec app yarn migration:run +``` diff --git a/QUICK-START.md b/QUICK-START.md new file mode 100644 index 0000000..508d9ea --- /dev/null +++ b/QUICK-START.md @@ -0,0 +1,178 @@ +# Quick Start Guide для GitHub Actions Deploy + +## 🚀 Быстрая настройка + +### 1. Настройка тестового сервера + +Запустите на своем тестовом сервере: + +```bash +# Скачать и запустить скрипт настройки +curl -sSL https://raw.githubusercontent.com/YOUR_USERNAME/YOUR_REPO/main/scripts/setup-testing-server.sh | bash +``` + +Или вручную: + +```bash +git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git +cd YOUR_REPO +./scripts/setup-testing-server.sh +``` + +### 2. Настройка SSH ключей + +На тестовом сервере добавьте свой публичный SSH ключ: + +```bash +# Генерация нового SSH ключа (если нужно) +ssh-keygen -t ed25519 -C "github-actions@yourdomain.com" -f ~/.ssh/github_actions + +# Добавление публичного ключа на сервер +sudo -u deploy tee -a /home/deploy/.ssh/authorized_keys < ~/.ssh/github_actions.pub +``` + +### 3. Настройка GitHub Secrets + +В настройках GitHub репозитория (Settings → Secrets and variables → Actions) добавьте: + +**Required Secrets:** + +``` +TESTING_SERVER_HOST=your.server.ip.address +TESTING_SERVER_USER=deploy +TESTING_SERVER_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY----- +your private key content here +-----END OPENSSH PRIVATE KEY----- +TESTING_DB_ROOT_PASSWORD=your_strong_root_password +TESTING_DB_USERNAME=app_user +TESTING_DB_PASSWORD=your_strong_user_password +``` + +**Optional Variables:** + +``` +TESTING_BASE_PORT=3000 +TESTING_BASE_DB_PORT=3300 +TESTING_BASE_REDIS_PORT=6300 +``` + +### 4. Тестирование + +1. Создайте новую ветку и сделайте изменения +2. Создайте Pull Request в ветку `develop` +3. GitHub Actions автоматически развернет приложение +4. Проверьте комментарий в PR с информацией о развертывании + +## 📝 Полезные команды на сервере + +```bash +# Мониторинг всех развертываний +sudo /usr/local/bin/monitor-deployments + +# Очистка старых развертываний +sudo /usr/local/bin/cleanup-old-deployments + +# Просмотр логов конкретного PR +cd /opt/low-code-engine/testing-pr-123 +docker-compose logs -f app + +# Проверка статуса контейнеров +docker-compose ps + +# Запуск миграций вручную +docker-compose exec app yarn migration:run +``` + +## 🔧 Troubleshooting + +### Проблема: "Permission denied" при SSH подключении + +```bash +# На сервере проверьте права доступа +sudo ls -la /home/deploy/.ssh/ +sudo cat /home/deploy/.ssh/authorized_keys + +# Права должны быть: +# drwx------ deploy deploy .ssh/ +# -rw------- deploy deploy authorized_keys +``` + +### Проблема: Порт уже занят + +```bash +# Найти процесс использующий порт +sudo netstat -tulpn | grep :3123 + +# Остановить все контейнеры для PR +cd /opt/low-code-engine/testing-pr-123 +docker-compose down +``` + +### Проблема: Не хватает места на диске + +```bash +# Очистить Docker ресурсы +docker system prune -a -f + +# Очистить старые развертывания +sudo /usr/local/bin/cleanup-old-deployments +``` + +### Проблема: База данных не запускается + +```bash +# Проверить логи MariaDB +docker-compose logs mariadb + +# Пересоздать контейнер базы данных +docker-compose down +docker-compose up -d mariadb +``` + +## 🌐 Доступ к приложениям + +### По портам (прямой доступ): + +- Приложение: `http://YOUR_SERVER_IP:3000{PR_NUMBER}` +- База данных: `YOUR_SERVER_IP:3300{PR_NUMBER}` +- Redis: `YOUR_SERVER_IP:6300{PR_NUMBER}` + +### Через домены (если настроен Nginx): + +- Приложение: `http://pr-{PR_NUMBER}.testing.yourdomain.com` + +Пример для PR #123: + +- Приложение: `http://your.server.ip:3123` или `http://pr-123.testing.yourdomain.com` +- База данных: `your.server.ip:3423` +- Redis: `your.server.ip:6423` + +## 📊 Мониторинг + +Проверить статус всех развертываний: + +```bash +sudo /usr/local/bin/monitor-deployments +``` + +Вывод будет примерно таким: + +``` +=== Testing Deployments Status === +Date: Mon Oct 13 10:30:00 UTC 2025 + +Active Deployments: + PR #123: Running on port 3123 + Status: ✅ Healthy + PR #124: Running on port 3124 + Status: ❌ Unhealthy + +=== System Resources === +Disk Usage: +/dev/sda1 20G 8.5G 11G 45% /opt/low-code-engine + +Docker Usage: +TYPE TOTAL ACTIVE SIZE RECLAIMABLE +Images 15 8 2.5GB 1.2GB (48%) +Containers 16 8 150MB 80MB (53%) +``` diff --git a/scripts/setup-testing-server.sh b/scripts/setup-testing-server.sh new file mode 100755 index 0000000..e579134 --- /dev/null +++ b/scripts/setup-testing-server.sh @@ -0,0 +1,293 @@ +#!/bin/bash + +# Quick setup script for testing server +# Run this script on your testing server to set up the environment + +set -e + +echo "🚀 Setting up testing server for Low Code Engine deployments..." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if running as root +if [[ $EUID -eq 0 ]]; then + print_error "This script should not be run as root for security reasons" + exit 1 +fi + +# Update system +print_status "Updating system packages..." +sudo apt update && sudo apt upgrade -y + +# Install Docker +print_status "Installing Docker..." +if ! command -v docker &> /dev/null; then + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + sudo usermod -aG docker $USER + rm get-docker.sh + print_status "Docker installed successfully" +else + print_status "Docker is already installed" +fi + +# Install Docker Compose +print_status "Installing Docker Compose..." +if ! command -v docker-compose &> /dev/null; then + sudo apt install docker-compose-plugin -y + print_status "Docker Compose installed successfully" +else + print_status "Docker Compose is already installed" +fi + +# Create deploy user +print_status "Creating deploy user..." +if ! id "deploy" &>/dev/null; then + sudo useradd -m -s /bin/bash deploy + sudo usermod -aG docker deploy + print_status "Deploy user created successfully" +else + print_status "Deploy user already exists" +fi + +# Setup SSH directory for deploy user +print_status "Setting up SSH for deploy user..." +sudo mkdir -p /home/deploy/.ssh +sudo chmod 700 /home/deploy/.ssh +sudo touch /home/deploy/.ssh/authorized_keys +sudo chmod 600 /home/deploy/.ssh/authorized_keys +sudo chown -R deploy:deploy /home/deploy/.ssh + +# Create application directory +print_status "Creating application directory..." +sudo mkdir -p /opt/low-code-engine +sudo chown deploy:deploy /opt/low-code-engine + +# Install nginx (optional) +print_status "Installing Nginx..." +if ! command -v nginx &> /dev/null; then + sudo apt install nginx -y + print_status "Nginx installed successfully" +else + print_status "Nginx is already installed" +fi + +# Create nginx configuration for testing apps +print_status "Creating Nginx configuration..." +sudo tee /etc/nginx/sites-available/testing-apps > /dev/null <\d+)\.testing\.(.+)$; + + # Health check endpoint + location /health { + set \$app_port 3000\$pr_number; + proxy_pass http://127.0.0.1:\$app_port; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + + # Add CORS headers for API calls + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always; + } + + # Main application + location / { + set \$app_port 3000\$pr_number; + proxy_pass http://127.0.0.1:\$app_port; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + + # WebSocket support + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } +} + +# Direct port access (fallback) +server { + listen 80 default_server; + server_name _; + + location / { + return 200 'Testing Server is running. Use pr-{NUMBER}.testing.yourdomain.com to access deployments.'; + add_header Content-Type text/plain; + } +} +EOF + +# Enable nginx configuration +if [ ! -L /etc/nginx/sites-enabled/testing-apps ]; then + sudo ln -s /etc/nginx/sites-available/testing-apps /etc/nginx/sites-enabled/ +fi + +# Remove default nginx site +if [ -L /etc/nginx/sites-enabled/default ]; then + sudo rm /etc/nginx/sites-enabled/default +fi + +# Test and reload nginx +sudo nginx -t && sudo systemctl reload nginx +print_status "Nginx configured successfully" + +# Install useful tools +print_status "Installing additional tools..." +sudo apt install -y curl wget htop netstat-nat jq + +# Create cleanup script +print_status "Creating cleanup script..." +sudo tee /usr/local/bin/cleanup-old-deployments > /dev/null <<'EOF' +#!/bin/bash +# Cleanup script for old testing deployments + +DAYS_OLD=7 +DEPLOYMENT_DIR="/opt/low-code-engine" + +echo "Cleaning up deployments older than ${DAYS_OLD} days..." + +find ${DEPLOYMENT_DIR} -name "testing-pr-*" -type d -mtime +${DAYS_OLD} | while read dir; do + echo "Cleaning up: $dir" + + # Stop containers if running + if [ -f "$dir/docker-compose.yml" ]; then + cd "$dir" + docker-compose down -v 2>/dev/null || true + fi + + # Remove directory + rm -rf "$dir" + echo "Removed: $dir" +done + +# Clean up unused Docker resources +docker system prune -f +docker image prune -f + +echo "Cleanup completed" +EOF + +sudo chmod +x /usr/local/bin/cleanup-old-deployments + +# Create cron job for cleanup +print_status "Setting up automatic cleanup..." +(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/cleanup-old-deployments") | crontab - + +# Create monitoring script +print_status "Creating monitoring script..." +sudo tee /usr/local/bin/monitor-deployments > /dev/null <<'EOF' +#!/bin/bash +# Monitoring script for testing deployments + +DEPLOYMENT_DIR="/opt/low-code-engine" + +echo "=== Testing Deployments Status ===" +echo "Date: $(date)" +echo + +# Show active deployments +echo "Active Deployments:" +find ${DEPLOYMENT_DIR} -name "testing-pr-*" -type d | sort | while read dir; do + pr_number=$(basename "$dir" | sed 's/testing-pr-//') + if [ -f "$dir/docker-compose.yml" ]; then + cd "$dir" + status=$(docker-compose ps -q | wc -l) + if [ "$status" -gt 0 ]; then + app_port=$((3000 + pr_number)) + echo " PR #${pr_number}: Running on port ${app_port}" + # Check if app is responding + if curl -s --max-time 5 "http://localhost:${app_port}/health" > /dev/null 2>&1; then + echo " Status: ✅ Healthy" + else + echo " Status: ❌ Unhealthy" + fi + else + echo " PR #${pr_number}: Stopped" + fi + fi +done + +echo +echo "=== System Resources ===" +echo "Disk Usage:" +df -h /opt/low-code-engine +echo +echo "Docker Usage:" +docker system df +echo +echo "Memory Usage:" +free -h +EOF + +sudo chmod +x /usr/local/bin/monitor-deployments + +# Setup firewall (optional but recommended) +print_status "Configuring firewall..." +if command -v ufw &> /dev/null; then + sudo ufw --force enable + sudo ufw allow ssh + sudo ufw allow 80/tcp + sudo ufw allow 443/tcp + # Allow port range for testing apps (3000-3999) + sudo ufw allow 3000:3999/tcp + # Allow port range for databases (3300-3999) + sudo ufw allow 3300:3999/tcp + # Allow port range for redis (6300-6999) + sudo ufw allow 6300:6999/tcp + print_status "Firewall configured" +else + print_warning "UFW not found, skipping firewall configuration" +fi + +print_status "Setup completed successfully!" +echo +echo "🎉 Your testing server is ready!" +echo +echo "Next steps:" +echo "1. Add your public SSH key to /home/deploy/.ssh/authorized_keys" +echo "2. Configure your GitHub repository secrets:" +echo " - TESTING_SERVER_HOST: $(curl -s ifconfig.me 2>/dev/null || echo 'YOUR_SERVER_IP')" +echo " - TESTING_SERVER_USER: deploy" +echo " - TESTING_SERVER_SSH_KEY: (your private SSH key)" +echo " - TESTING_DB_ROOT_PASSWORD: (choose a strong password)" +echo " - TESTING_DB_USERNAME: app_user" +echo " - TESTING_DB_PASSWORD: (choose a strong password)" +echo +echo "Useful commands:" +echo " - Monitor deployments: sudo /usr/local/bin/monitor-deployments" +echo " - Cleanup old deployments: sudo /usr/local/bin/cleanup-old-deployments" +echo " - Check nginx status: sudo systemctl status nginx" +echo " - View nginx logs: sudo journalctl -u nginx -f" +echo +print_warning "Please reboot the server or run 'newgrp docker' to apply Docker group changes" +EOF \ No newline at end of file