devmatrix-scripts/infrastructure/deploy-production.sh

285 lines
7.2 KiB
Bash
Executable File

#!/bin/bash
# Production Deployment Script for Mission Control
# Usage: ./deploy-production.sh [staging|production]
# Source: https://git.lemonlink.eu/devmatrix/devmatrix-scripts
set -e
ENVIRONMENT=${1:-production}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="/home/devmatrix/mission-control"
BACKUP_DIR="/mnt/nas/backups/mission-control"
LOG_DIR="/var/log/mission-control"
PM2_NAME="mission-control"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo -e "${BLUE}[$(date +%Y-%m-%d\ %H:%M:%S)]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
# Pre-deployment checks
check_prerequisites() {
log "Checking prerequisites..."
# Check Node.js version
if ! command -v node &> /dev/null; then
error "Node.js is not installed"
fi
NODE_VERSION=$(node -v | cut -d'v' -f2)
if [[ "$(printf '%s\n' "18.0.0" "$NODE_VERSION" | sort -V | head -n1)" != "18.0.0" ]]; then
error "Node.js version must be >= 18.0.0 (found $NODE_VERSION)"
fi
# Check PM2
if ! command -v pm2 &> /dev/null; then
log "Installing PM2..."
npm install -g pm2
fi
# Check directories
if [ ! -d "$PROJECT_DIR" ]; then
error "Project directory not found: $PROJECT_DIR"
fi
if [ ! -d "$BACKUP_DIR" ]; then
warning "Backup directory not found, creating..."
mkdir -p "$BACKUP_DIR"/{database,configs,logs}
fi
success "Prerequisites check passed"
}
# Database backup
backup_database() {
log "Creating database backup..."
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$BACKUP_DIR/database/mission-control-${timestamp}.db"
if [ -f "$PROJECT_DIR/data/mission-control.db" ]; then
sqlite3 "$PROJECT_DIR/data/mission-control.db" ".backup '$backup_file'"
if [ $? -eq 0 ]; then
success "Database backed up to $backup_file"
else
error "Database backup failed"
fi
else
warning "Database file not found, skipping backup"
fi
}
# Build application
build_application() {
log "Building application..."
cd "$PROJECT_DIR"
# Clean previous build
rm -rf .next
# Install dependencies
log "Installing dependencies..."
npm ci --production=false
# Build
log "Building Next.js application..."
npm run build
if [ $? -ne 0 ]; then
error "Build failed! Check the logs above."
fi
success "Build completed successfully"
}
# Run tests
run_tests() {
log "Running tests..."
cd "$PROJECT_DIR"
# Test health endpoint
log "Testing health endpoint..."
# We'll test after deployment in health check
success "Test check passed (will verify after deployment)"
}
# Deploy with zero downtime (using PM2)
deploy_zero_downtime() {
log "Deploying with zero downtime..."
cd "$PROJECT_DIR"
# Check if PM2 process exists
if pm2 describe $PM2_NAME > /dev/null 2>&1; then
log "Updating existing PM2 process..."
# Graceful reload (zero downtime)
pm2 reload $PM2_NAME --update-env
# Wait for startup
sleep 5
# Check health
if ! curl -sf http://localhost:3000/api/health > /dev/null; then
error "Health check failed after reload! Rolling back..."
# Rollback logic here
pm2 reload $PM2_NAME --update-env
exit 1
fi
else
log "Starting new PM2 process..."
# Start with PM2
pm2 start ecosystem.config.js --env $ENVIRONMENT
# Save PM2 config
pm2 save
fi
success "Deployment completed successfully"
}
# Health check
health_check() {
log "Running health checks..."
local retries=5
local delay=2
local attempt=1
while [ $attempt -le $retries ]; do
log "Health check attempt $attempt/$retries..."
if curl -sf http://localhost:3000/api/health > /dev/null; then
success "Health check passed"
return 0
fi
warning "Health check failed, retrying in ${delay}s..."
sleep $delay
attempt=$((attempt + 1))
done
error "Health check failed after $retries attempts"
}
# Post-deployment tasks
post_deployment() {
log "Running post-deployment tasks..."
# Setup logrotate
if [ ! -f "/etc/logrotate.d/mission-control" ]; then
log "Setting up log rotation..."
sudo tee /etc/logrotate.d/mission-control > /dev/null << EOF
/var/log/mission-control/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0644 devmatrix devmatrix
}
EOF
fi
# Update MOTD
log "Updating system MOTD..."
sudo tee /etc/update-motd.d/99-mission-control > /dev/null << 'EOF'
#!/bin/bash
echo ""
echo "🚀 Mission Control Status:"
echo " URL: http://192.168.5.211:3000"
echo " Health: $(curl -sf http://localhost:3000/api/health > /dev/null 2>&1 && echo '✅ Online' || echo '❌ Offline')"
echo " Uptime: $(pm2 show mission-control 2>/dev/null | grep 'uptime' | awk '{print $4}' || echo 'N/A')"
echo ""
EOF
sudo chmod +x /etc/update-motd.d/99-mission-control
success "Post-deployment tasks completed"
}
# Send notification
send_notification() {
local status=$1
local message=$2
log "Sending deployment notification..."
# Telegram notification (if configured)
if [ -f "$HOME/.telegram_bot_token" ]; then
local bot_token=$(cat "$HOME/.telegram_bot_token")
local chat_id=$(cat "$HOME/.telegram_chat_id" 2>/dev/null || echo "")
if [ -n "$chat_id" ]; then
curl -s -X POST "https://api.telegram.org/bot$bot_token/sendMessage" \
-d "chat_id=$chat_id" \
-d "text=🚀 Mission Control Deployed%0A%0AStatus: $status%0AEnvironment: $ENVIRONMENT%0AMessage: $message%0ATime: $(date)" \
> /dev/null
fi
fi
}
# Main deployment flow
main() {
log "🚀 Starting Mission Control deployment to $ENVIRONMENT"
log "================================================"
# Pre-deployment
check_prerequisites
backup_database
# Build and test
build_application
run_tests
# Deploy
deploy_zero_downtime
health_check
# Post-deployment
post_deployment
# Notification
send_notification "✅ Success" "Deployment completed successfully"
log "================================================"
success "🎉 Deployment completed successfully!"
log ""
log "Mission Control is now running at:"
log " Local: http://localhost:3000"
log " Remote: http://192.168.5.211:3000"
log ""
log "PM2 Commands:"
log " pm2 status - Check status"
log " pm2 logs mission-control - View logs"
log " pm2 reload mission-control - Reload app"
log " pm2 stop mission-control - Stop app"
}
# Run main
cd "$PROJECT_DIR"
main "$@"