#!/bin/bash # Deployment script for BackgroundFX Pro # Handles deployment to various environments set -e # Configuration SCRIPT_DIR=$(dirname $(realpath $0)) PROJECT_ROOT=$(dirname $SCRIPT_DIR) TIMESTAMP=$(date +%Y%m%d_%H%M%S) # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Default values ENVIRONMENT="production" DEPLOY_METHOD="docker" REGISTRY="" VERSION="latest" BACKUP=true # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --env) ENVIRONMENT="$2" shift 2 ;; --method) DEPLOY_METHOD="$2" shift 2 ;; --registry) REGISTRY="$2" shift 2 ;; --version) VERSION="$2" shift 2 ;; --no-backup) BACKUP=false shift ;; --help) show_help exit 0 ;; *) echo -e "${RED}Unknown option: $1${NC}" show_help exit 1 ;; esac done show_help() { cat << EOF Usage: $0 [OPTIONS] Deploy BackgroundFX Pro to various environments Options: --env ENV Environment (development, staging, production) [default: production] --method METHOD Deployment method (docker, kubernetes, server) [default: docker] --registry REGISTRY Container registry URL --version VERSION Version to deploy [default: latest] --no-backup Skip backup before deployment --help Show this help message Examples: $0 --env production --method docker $0 --env staging --registry myregistry.com --version 1.0.0 $0 --env development --no-backup EOF } # Deployment functions deploy_docker() { echo -e "${BLUE}Deploying with Docker to ${ENVIRONMENT}...${NC}" cd "$PROJECT_ROOT" # Build images echo "Building Docker images..." if [ "$ENVIRONMENT" = "production" ]; then docker build -f docker/Dockerfile.prod -t backgroundfx-pro:$VERSION . else docker build -f docker/Dockerfile -t backgroundfx-pro:$VERSION . fi # Tag for registry if specified if [ -n "$REGISTRY" ]; then docker tag backgroundfx-pro:$VERSION $REGISTRY/backgroundfx-pro:$VERSION docker push $REGISTRY/backgroundfx-pro:$VERSION echo -e "${GREEN}✓ Pushed to registry: $REGISTRY${NC}" fi # Deploy with docker-compose if [ "$ENVIRONMENT" = "production" ]; then docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d else docker-compose up -d fi echo -e "${GREEN}✓ Docker deployment complete${NC}" } deploy_kubernetes() { echo -e "${BLUE}Deploying to Kubernetes cluster...${NC}" cd "$PROJECT_ROOT/kubernetes" # Check kubectl if ! command -v kubectl &> /dev/null; then echo -e "${RED}kubectl not found${NC}" exit 1 fi # Apply configurations echo "Applying Kubernetes configurations..." # Create namespace if not exists kubectl create namespace backgroundfx --dry-run=client -o yaml | kubectl apply -f - # Apply configs based on environment if [ "$ENVIRONMENT" = "production" ]; then kubectl apply -f configmap-prod.yaml kubectl apply -f secret-prod.yaml kubectl apply -f deployment-prod.yaml kubectl apply -f service-prod.yaml kubectl apply -f ingress-prod.yaml else kubectl apply -f configmap.yaml kubectl apply -f deployment.yaml kubectl apply -f service.yaml fi # Wait for deployment echo "Waiting for deployment to be ready..." kubectl rollout status deployment/backgroundfx-pro -n backgroundfx # Get service info echo -e "\n${GREEN}Deployment complete!${NC}" kubectl get services -n backgroundfx kubectl get pods -n backgroundfx } deploy_server() { echo -e "${BLUE}Deploying to server...${NC}" # Check for required environment variables if [ -z "$DEPLOY_HOST" ] || [ -z "$DEPLOY_USER" ]; then echo -e "${RED}Error: DEPLOY_HOST and DEPLOY_USER must be set${NC}" exit 1 fi cd "$PROJECT_ROOT" # Create deployment package echo "Creating deployment package..." PACKAGE_NAME="backgroundfx_${VERSION}_${TIMESTAMP}.tar.gz" tar -czf "/tmp/$PACKAGE_NAME" \ --exclude="*.pyc" \ --exclude="__pycache__" \ --exclude=".git" \ --exclude="venv" \ --exclude="*.log" \ --exclude="outputs/*" \ --exclude="uploads/*" \ . # Upload to server echo "Uploading to $DEPLOY_HOST..." scp "/tmp/$PACKAGE_NAME" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" # Deploy on server echo "Deploying on server..." ssh "$DEPLOY_USER@$DEPLOY_HOST" << EOF # Create deployment directory mkdir -p /opt/backgroundfx/releases/$VERSION # Extract package tar -xzf /tmp/$PACKAGE_NAME -C /opt/backgroundfx/releases/$VERSION # Stop current service sudo systemctl stop backgroundfx || true # Update symlink rm -f /opt/backgroundfx/current ln -s /opt/backgroundfx/releases/$VERSION /opt/backgroundfx/current # Install dependencies cd /opt/backgroundfx/current python3 -m venv venv source venv/bin/activate pip install -r requirements.txt # Start service sudo systemctl start backgroundfx sudo systemctl status backgroundfx EOF # Cleanup rm "/tmp/$PACKAGE_NAME" echo -e "${GREEN}✓ Server deployment complete${NC}" } # Health check health_check() { echo -e "\n${BLUE}Running health check...${NC}" # Determine URL based on environment if [ "$ENVIRONMENT" = "production" ]; then URL="https://app.backgroundfx.com/health" elif [ "$ENVIRONMENT" = "staging" ]; then URL="https://staging.backgroundfx.com/health" else URL="http://localhost:7860/health" fi # Check health endpoint if curl -f -s "$URL" > /dev/null; then echo -e "${GREEN}✓ Application is healthy${NC}" curl -s "$URL" | python -m json.tool else echo -e "${RED}✗ Health check failed${NC}" return 1 fi } # Backup function create_backup() { if [ "$BACKUP" = false ]; then return fi echo -e "${BLUE}Creating backup...${NC}" BACKUP_DIR="$PROJECT_ROOT/backups/$TIMESTAMP" mkdir -p "$BACKUP_DIR" # Backup database if exists if [ -f "$PROJECT_ROOT/database.db" ]; then cp "$PROJECT_ROOT/database.db" "$BACKUP_DIR/" fi # Backup configurations cp -r "$PROJECT_ROOT/config" "$BACKUP_DIR/" 2>/dev/null || true # Backup docker volumes if using Docker if [ "$DEPLOY_METHOD" = "docker" ]; then docker run --rm \ -v backgroundfx-pro_model-cache:/data \ -v "$BACKUP_DIR":/backup \ alpine tar czf /backup/models.tar.gz -C /data . 2>/dev/null || true fi echo -e "${GREEN}✓ Backup created: $BACKUP_DIR${NC}" } # Rollback function rollback() { echo -e "${YELLOW}Rolling back deployment...${NC}" if [ "$DEPLOY_METHOD" = "docker" ]; then # Docker rollback docker-compose down docker tag backgroundfx-pro:previous backgroundfx-pro:$VERSION docker-compose up -d elif [ "$DEPLOY_METHOD" = "kubernetes" ]; then # Kubernetes rollback kubectl rollout undo deployment/backgroundfx-pro -n backgroundfx elif [ "$DEPLOY_METHOD" = "server" ]; then # Server rollback ssh "$DEPLOY_USER@$DEPLOY_HOST" << EOF rm /opt/backgroundfx/current ln -s /opt/backgroundfx/releases/previous /opt/backgroundfx/current sudo systemctl restart backgroundfx EOF fi echo -e "${GREEN}✓ Rollback complete${NC}" } # Pre-deployment checks pre_deploy_checks() { echo -e "${BLUE}Running pre-deployment checks...${NC}" # Check git status if [ -d .git ]; then if [ -n "$(git status --porcelain)" ]; then echo -e "${YELLOW}Warning: Uncommitted changes detected${NC}" read -p "Continue anyway? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi fi fi # Run tests echo "Running tests..." if command -v pytest &> /dev/null; then pytest tests/ -m "not slow" --quiet || { echo -e "${RED}Tests failed${NC}" read -p "Deploy anyway? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi } else echo -e "${YELLOW}pytest not found, skipping tests${NC}" fi echo -e "${GREEN}✓ Pre-deployment checks passed${NC}" } # Main deployment flow main() { echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}BackgroundFX Pro Deployment${NC}" echo -e "${BLUE}========================================${NC}" echo "Environment: $ENVIRONMENT" echo "Method: $DEPLOY_METHOD" echo "Version: $VERSION" echo # Run pre-deployment checks pre_deploy_checks # Create backup create_backup # Deploy based on method case $DEPLOY_METHOD in docker) deploy_docker ;; kubernetes) deploy_kubernetes ;; server) deploy_server ;; *) echo -e "${RED}Invalid deployment method: $DEPLOY_METHOD${NC}" exit 1 ;; esac # Run health check sleep 5 if health_check; then echo -e "\n${GREEN}========================================${NC}" echo -e "${GREEN}Deployment Successful!${NC}" echo -e "${GREEN}========================================${NC}" else echo -e "\n${RED}Deployment may have issues${NC}" read -p "Rollback? (y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then rollback fi fi } # Trap errors trap 'echo -e "${RED}Deployment failed!${NC}"; exit 1' ERR # Run main function main