146 lines
4.5 KiB
Bash
146 lines
4.5 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# IGNY8 Deploy to Production
|
|
# =============================================================================
|
|
# Safely deploys code to production with backup and rollback capability
|
|
# Usage: ./deploy-production.sh
|
|
# =============================================================================
|
|
|
|
set -e
|
|
|
|
APP_DIR="/data/app/igny8"
|
|
COMPOSE_FILE="docker-compose.app.yml"
|
|
PROJECT_NAME="igny8-app"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log() {
|
|
echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}✅ $1${NC}"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}❌ $1${NC}"
|
|
}
|
|
|
|
echo "=========================================="
|
|
echo "IGNY8 PRODUCTION DEPLOYMENT"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Safety confirmation
|
|
log_warn "This will deploy to PRODUCTION!"
|
|
log_warn "Make sure you have tested on staging first."
|
|
echo ""
|
|
read -p "Type 'deploy' to continue: " confirm
|
|
if [[ "${confirm}" != "deploy" ]]; then
|
|
log "Deployment cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
cd "${APP_DIR}"
|
|
|
|
# Verify on main branch
|
|
CURRENT_BRANCH=$(git branch --show-current)
|
|
if [[ "${CURRENT_BRANCH}" != "main" ]]; then
|
|
log_error "Not on main branch (currently on: ${CURRENT_BRANCH})"
|
|
log "Switch to main: git checkout main && git pull"
|
|
exit 1
|
|
fi
|
|
|
|
# Step 1: Create pre-deploy backup
|
|
log "Step 1/8: Creating pre-deploy backup..."
|
|
/data/app/igny8/scripts/ops/backup-db.sh pre-deploy
|
|
log_success "Backup created"
|
|
|
|
# Step 2: Tag current images for rollback
|
|
log "Step 2/8: Tagging current images for rollback..."
|
|
docker tag igny8-backend:latest igny8-backend:rollback 2>/dev/null || true
|
|
docker tag igny8-frontend-dev:latest igny8-frontend-dev:rollback 2>/dev/null || true
|
|
docker tag igny8-marketing-dev:latest igny8-marketing-dev:rollback 2>/dev/null || true
|
|
log_success "Rollback images tagged"
|
|
|
|
# Step 3: Pull latest code
|
|
log "Step 3/8: Pulling latest code..."
|
|
git pull origin main
|
|
log_success "Code updated"
|
|
|
|
# Step 4: Build new images
|
|
log "Step 4/8: Building new images..."
|
|
docker build -t igny8-backend:latest -f backend/Dockerfile backend/
|
|
docker build -t igny8-frontend-dev:latest -f frontend/Dockerfile.dev frontend/
|
|
docker build -t igny8-marketing-dev:latest -f frontend/Dockerfile.marketing.dev frontend/
|
|
log_success "Images built"
|
|
|
|
# Step 5: Check for pending migrations
|
|
log "Step 5/8: Checking for pending migrations..."
|
|
PENDING=$(docker exec igny8_backend python manage.py showmigrations --plan 2>/dev/null | grep "\[ \]" || true)
|
|
if [[ -n "${PENDING}" ]]; then
|
|
log_warn "Pending migrations found:"
|
|
echo "${PENDING}"
|
|
read -p "Apply migrations? (yes/no): " apply_migrations
|
|
if [[ "${apply_migrations}" != "yes" ]]; then
|
|
log "Skipping migrations"
|
|
fi
|
|
fi
|
|
|
|
# Step 6: Restart containers
|
|
log "Step 6/8: Restarting containers..."
|
|
docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" down
|
|
docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" up -d
|
|
|
|
# Step 7: Wait for backend to be healthy
|
|
log "Step 7/8: Waiting for backend to be healthy..."
|
|
for i in {1..30}; do
|
|
if docker exec igny8_backend python -c "import urllib.request; urllib.request.urlopen('http://localhost:8010/api/v1/system/status/').read()" 2>/dev/null; then
|
|
log_success "Backend is healthy"
|
|
break
|
|
fi
|
|
if [[ $i -eq 30 ]]; then
|
|
log_error "Backend failed to become healthy"
|
|
log_error "ROLLING BACK..."
|
|
/data/app/igny8/scripts/ops/rollback.sh --auto
|
|
exit 1
|
|
fi
|
|
echo -n "."
|
|
sleep 2
|
|
done
|
|
|
|
# Step 8: Apply migrations and collect static
|
|
log "Step 8/8: Applying migrations and collecting static..."
|
|
if [[ "${apply_migrations}" == "yes" ]] || [[ -z "${PENDING}" ]]; then
|
|
docker exec igny8_backend python manage.py migrate --noinput
|
|
fi
|
|
docker exec igny8_backend python manage.py collectstatic --noinput
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
log_success "PRODUCTION DEPLOYMENT COMPLETE"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "Production is live!"
|
|
echo " App: https://app.igny8.com"
|
|
echo " API: https://api.igny8.com"
|
|
echo ""
|
|
echo "Monitor logs for 10 minutes:"
|
|
echo " docker compose -f ${COMPOSE_FILE} -p ${PROJECT_NAME} logs -f"
|
|
echo ""
|
|
echo "If issues occur, rollback:"
|
|
echo " /data/app/igny8/scripts/ops/rollback.sh"
|
|
echo ""
|
|
echo "Container status:"
|
|
docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" ps
|
|
echo "=========================================="
|