name: Deploy to Docker on: workflow_dispatch: inputs: mode: description: 'Deployment mode' required: true default: 'multiuser' type: choice options: - solo - multiuser - enterprise dry_run: description: 'Perform dry-run (no actual deployment)' required: false default: 'false' type: choice options: - 'true' - 'false' environment: description: 'Target environment' required: true type: choice options: - development - staging - production workflow_run: workflows: [Validate & Build Artifacts] types: [completed] branches: [develop] concurrency: group: docker-deployment-${{ github.ref }} cancel-in-progress: false jobs: deploy-docker: name: Deploy ${{ inputs.mode || 'multiuser' }} to Docker runs-on: ubuntu-latest environment: ${{ inputs.environment || 'staging' }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: name: deployment-artifacts path: artifacts/ - name: Install Nushell run: | cargo install nu --locked nu --version - name: Install Docker & Docker Compose run: | sudo apt-get update sudo apt-get install -y docker.io docker-compose docker --version docker compose --version - name: Create docker-compose directory run: | mkdir -p deploy/docker cp artifacts/docker-compose.yml deploy/docker/ cp artifacts/vapora-${{ inputs.mode || 'multiuser' }}.yaml deploy/docker/config.yaml - name: Start Docker daemon run: sudo service docker start - name: Create Docker network run: | docker network create vapora || true continue-on-error: true - name: Pull base images run: | docker pull surrealdb/surrealdb:latest || true docker pull nats:latest || true continue-on-error: true - name: Validate Docker Compose run: | cd deploy/docker docker compose config > /dev/null continue-on-error: false - name: Perform dry-run if: ${{ inputs.dry_run == 'true' || github.event_name == 'workflow_run' }} run: | cd deploy/docker echo "🔍 Dry-run: Validating Docker Compose configuration" docker compose config docker compose --dry-run up --no-build 2>&1 || true continue-on-error: true - name: Deploy to Docker Compose if: ${{ inputs.dry_run == 'false' && github.event_name != 'workflow_run' }} run: | cd deploy/docker echo "🚀 Starting Docker Compose services..." docker compose up -d echo "⏳ Waiting for services to start (10s)..." sleep 10 docker compose ps - name: Check service health (Docker) if: ${{ inputs.dry_run == 'false' && github.event_name != 'workflow_run' }} run: | echo "🏥 Checking service health..." # SurrealDB for i in {1..5}; do if curl -sf http://localhost:8000/health > /dev/null; then echo "✓ SurrealDB healthy" break fi echo "Attempt $i/5 for SurrealDB..." sleep 2 done # Backend for i in {1..5}; do if curl -sf http://localhost:8001/health > /dev/null; then echo "✓ Backend healthy" break fi echo "Attempt $i/5 for Backend..." sleep 2 done # Frontend for i in {1..5}; do if curl -sf http://localhost:3000 > /dev/null; then echo "✓ Frontend healthy" break fi echo "Attempt $i/5 for Frontend..." sleep 2 done - name: Display deployment status if: always() run: | cd deploy/docker echo "📊 Container Status:" docker compose ps echo "" echo "📋 Service Logs (last 20 lines):" docker compose logs --tail=20 - name: Save deployment details if: success() run: | cat > deploy/docker/DEPLOYMENT.md << 'EOF' # Docker Deployment Details **Deployment Time**: $(date -u +'%Y-%m-%dT%H:%M:%SZ') **Mode**: ${{ inputs.mode || 'multiuser' }} **Environment**: ${{ inputs.environment || 'staging' }} **Commit**: ${{ github.sha }} **Workflow Run**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} ## Services ### Available Endpoints - **Backend API**: http://localhost:8001 - **Health Check**: http://localhost:8001/health - **Frontend**: http://localhost:3000 - **Agents**: http://localhost:8002 - **LLM Router**: http://localhost:8003 - **SurrealDB**: http://localhost:8000 - **NATS**: nats://localhost:4222 (if enabled) - **Prometheus**: http://localhost:9090 (if enabled) ## Management Commands ### View logs ```bash docker compose -f docker-compose.yml logs -f docker compose logs backend ``` ### Stop services ```bash docker compose down ``` ### Restart service ```bash docker compose restart backend ``` ### Check health ```bash curl http://localhost:8001/health ``` ## Configuration - Mode: ${{ inputs.mode || 'multiuser' }} - Deployment Type: Docker Compose - Network: vapora (bridge) - Persistence: Named volumes (surrealdb_data, vapora_storage) EOF cat deploy/docker/DEPLOYMENT.md - name: Upload deployment logs if: always() uses: actions/upload-artifact@v4 with: name: docker-deployment-logs-${{ github.run_id }} path: deploy/docker/ retention-days: 30 - name: Post deployment notification if: success() uses: actions/github-script@v7 with: script: | const mode = '${{ inputs.mode || "multiuser" }}'; const isDryRun = '${{ inputs.dry_run }}' === 'true'; let message = `✅ **Docker deployment successful!**\n\n`; message += `**Mode**: ${mode}\n`; message += `**Dry-run**: ${isDryRun ? 'Yes' : 'No'}\n\n`; message += `**Services**:\n`; message += `- Backend: http://localhost:8001\n`; message += `- Frontend: http://localhost:3000\n`; message += `- Health: http://localhost:8001/health\n`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: message }); - name: Notify Slack on success if: success() uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} text: | VAPORA Docker deployment successful! Mode: ${{ inputs.mode || 'multiuser' }} Environment: ${{ inputs.environment || 'staging' }} webhook_url: ${{ secrets.SLACK_WEBHOOK }} fields: repo,message,commit,author continue-on-error: true - name: Notify Slack on failure if: failure() uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} text: 'VAPORA Docker deployment failed' webhook_url: ${{ secrets.SLACK_WEBHOOK }} fields: repo,message,commit,author continue-on-error: true