257 lines
6.2 KiB
Bash
257 lines
6.2 KiB
Bash
#!/bin/bash
|
|
|
|
# ==========================================
|
|
# XFlow Server Deployment Script
|
|
# ==========================================
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
COMPOSE_FILE="docker-compose.prod.yml"
|
|
BACKUP_DIR="./backups"
|
|
LOG_FILE="./logs/deploy-$(date +%Y%m%d-%H%M%S).log"
|
|
|
|
# ==========================================
|
|
# Helper Functions
|
|
# ==========================================
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# ==========================================
|
|
# Pre-deployment Checks
|
|
# ==========================================
|
|
|
|
check_prerequisites() {
|
|
log "Checking prerequisites..."
|
|
|
|
# Check Docker
|
|
if ! command -v docker &> /dev/null; then
|
|
error "Docker is not installed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check Docker Compose
|
|
if ! docker compose version &> /dev/null; then
|
|
error "Docker Compose is not installed"
|
|
exit 1
|
|
fi
|
|
|
|
# Check .env file
|
|
if [ ! -f .env ]; then
|
|
error ".env file not found. Please create it from .env.example"
|
|
exit 1
|
|
fi
|
|
|
|
# Check compose file
|
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
|
error "Compose file $COMPOSE_FILE not found"
|
|
exit 1
|
|
fi
|
|
|
|
success "Prerequisites check passed"
|
|
}
|
|
|
|
# ==========================================
|
|
# Backup
|
|
# ==========================================
|
|
|
|
create_backup() {
|
|
log "Creating backup..."
|
|
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# Backup database
|
|
if docker compose ps postgres | grep -q "running"; then
|
|
log "Backing up PostgreSQL database..."
|
|
docker compose exec -T postgres pg_dump -U gitea gitea > "$BACKUP_DIR/db-$(date +%Y%m%d-%H%M%S).sql" 2>/dev/null || warning "Database backup failed"
|
|
fi
|
|
|
|
success "Backup completed"
|
|
}
|
|
|
|
# ==========================================
|
|
# Deployment
|
|
# ==========================================
|
|
|
|
deploy() {
|
|
log "Starting deployment..."
|
|
|
|
# Pull latest images
|
|
log "Pulling latest images..."
|
|
docker compose -f "$COMPOSE_FILE" pull
|
|
|
|
# Deploy with zero downtime
|
|
log "Deploying services..."
|
|
docker compose -f "$COMPOSE_FILE" up -d --remove-orphans
|
|
|
|
success "Deployment completed"
|
|
}
|
|
|
|
# ==========================================
|
|
# Health Checks
|
|
# ==========================================
|
|
|
|
health_check() {
|
|
log "Running health checks..."
|
|
|
|
local max_attempts=30
|
|
local attempt=1
|
|
|
|
# Wait for services to start
|
|
sleep 10
|
|
|
|
# Check API
|
|
log "Checking API health..."
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if curl -sf http://localhost:8080/health > /dev/null 2>&1; then
|
|
success "API is healthy"
|
|
break
|
|
fi
|
|
|
|
if [ $attempt -eq $max_attempts ]; then
|
|
error "API health check failed after $max_attempts attempts"
|
|
show_logs
|
|
exit 1
|
|
fi
|
|
|
|
log "Attempt $attempt/$max_attempts: API not ready yet..."
|
|
sleep 5
|
|
((attempt++))
|
|
done
|
|
|
|
# Check Gitea
|
|
log "Checking Gitea health..."
|
|
attempt=1
|
|
while [ $attempt -le $max_attempts ]; do
|
|
if curl -sf http://localhost:3000/api/healthz > /dev/null 2>&1; then
|
|
success "Gitea is healthy"
|
|
break
|
|
fi
|
|
|
|
if [ $attempt -eq $max_attempts ]; then
|
|
warning "Gitea health check failed (may still be initializing)"
|
|
break
|
|
fi
|
|
|
|
log "Attempt $attempt/$max_attempts: Gitea not ready yet..."
|
|
sleep 5
|
|
((attempt++))
|
|
done
|
|
|
|
success "All health checks passed"
|
|
}
|
|
|
|
# ==========================================
|
|
# Cleanup
|
|
# ==========================================
|
|
|
|
cleanup() {
|
|
log "Cleaning up..."
|
|
|
|
# Remove old backups (keep last 7)
|
|
if [ -d "$BACKUP_DIR" ]; then
|
|
ls -t "$BACKUP_DIR"/*.sql 2>/dev/null | tail -n +8 | xargs -r rm
|
|
ls -t "$BACKUP_DIR"/*.tar.gz 2>/dev/null | tail -n +8 | xargs -r rm
|
|
fi
|
|
|
|
# Clean Docker
|
|
docker system prune -f
|
|
docker volume prune -f
|
|
|
|
success "Cleanup completed"
|
|
}
|
|
|
|
# ==========================================
|
|
# Rollback
|
|
# ==========================================
|
|
|
|
rollback() {
|
|
error "Deployment failed! Rolling back..."
|
|
|
|
# Get previous image
|
|
local previous_image=$(docker images ghcr.io/*/xflow-api --format "{{.Repository}}:{{.Tag}}" | grep -v latest | head -1)
|
|
|
|
if [ -n "$previous_image" ]; then
|
|
log "Reverting to: $previous_image"
|
|
docker compose -f "$COMPOSE_FILE" stop api
|
|
docker compose -f "$COMPOSE_FILE" rm -f api
|
|
docker run -d --name xflow-api-rollback \
|
|
--network xflow-network \
|
|
-e NODE_ENV=production \
|
|
-e PORT=8080 \
|
|
-p 8080:8080 \
|
|
"$previous_image"
|
|
success "Rollback completed"
|
|
else
|
|
error "No previous image found for rollback"
|
|
fi
|
|
}
|
|
|
|
# ==========================================
|
|
# Show Logs
|
|
# ==========================================
|
|
|
|
show_logs() {
|
|
log "Showing recent logs..."
|
|
docker compose -f "$COMPOSE_FILE" logs --tail=50
|
|
}
|
|
|
|
# ==========================================
|
|
# Main
|
|
# ==========================================
|
|
|
|
main() {
|
|
log "======================================"
|
|
log "XFlow Server Deployment"
|
|
log "======================================"
|
|
|
|
# Create logs directory
|
|
mkdir -p logs
|
|
|
|
# Run deployment steps
|
|
check_prerequisites
|
|
create_backup
|
|
|
|
# Deploy with error handling
|
|
if deploy; then
|
|
if health_check; then
|
|
cleanup
|
|
success "======================================"
|
|
success "Deployment completed successfully!"
|
|
success "======================================"
|
|
log "API: http://localhost:8080"
|
|
log "Gitea: http://localhost:3000"
|
|
else
|
|
rollback
|
|
exit 1
|
|
fi
|
|
else
|
|
rollback
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|