| #!/bin/bash |
| |
| |
|
|
| set -e |
|
|
| |
| SCRIPT_DIR=$(dirname $(realpath $0)) |
| PROJECT_ROOT=$(dirname $SCRIPT_DIR) |
| TIMESTAMP=$(date +%Y%m%d_%H%M%S) |
|
|
| |
| RED='\033[0;31m' |
| GREEN='\033[0;32m' |
| YELLOW='\033[1;33m' |
| BLUE='\033[0;34m' |
| NC='\033[0m' |
|
|
| |
| ENVIRONMENT="production" |
| DEPLOY_METHOD="docker" |
| REGISTRY="" |
| VERSION="latest" |
| BACKUP=true |
|
|
| |
| 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 |
| } |
|
|
| |
| deploy_docker() { |
| echo -e "${BLUE}Deploying with Docker to ${ENVIRONMENT}...${NC}" |
| |
| cd "$PROJECT_ROOT" |
| |
| |
| 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 |
| |
| |
| 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 |
| |
| |
| 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" |
| |
| |
| if ! command -v kubectl &> /dev/null; then |
| echo -e "${RED}kubectl not found${NC}" |
| exit 1 |
| fi |
| |
| |
| echo "Applying Kubernetes configurations..." |
| |
| |
| kubectl create namespace backgroundfx --dry-run=client -o yaml | kubectl apply -f - |
| |
| |
| 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 |
| |
| |
| echo "Waiting for deployment to be ready..." |
| kubectl rollout status deployment/backgroundfx-pro -n backgroundfx |
| |
| |
| 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}" |
| |
| |
| 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" |
| |
| |
| 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/*" \ |
| . |
| |
| |
| echo "Uploading to $DEPLOY_HOST..." |
| scp "/tmp/$PACKAGE_NAME" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/" |
| |
| |
| 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 |
| |
| |
| rm "/tmp/$PACKAGE_NAME" |
| |
| echo -e "${GREEN}✓ Server deployment complete${NC}" |
| } |
|
|
| |
| health_check() { |
| echo -e "\n${BLUE}Running health check...${NC}" |
| |
| |
| 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 |
| |
| |
| 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 |
| } |
|
|
| |
| create_backup() { |
| if [ "$BACKUP" = false ]; then |
| return |
| fi |
| |
| echo -e "${BLUE}Creating backup...${NC}" |
| |
| BACKUP_DIR="$PROJECT_ROOT/backups/$TIMESTAMP" |
| mkdir -p "$BACKUP_DIR" |
| |
| |
| if [ -f "$PROJECT_ROOT/database.db" ]; then |
| cp "$PROJECT_ROOT/database.db" "$BACKUP_DIR/" |
| fi |
| |
| |
| cp -r "$PROJECT_ROOT/config" "$BACKUP_DIR/" 2>/dev/null || true |
| |
| |
| 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() { |
| echo -e "${YELLOW}Rolling back deployment...${NC}" |
| |
| if [ "$DEPLOY_METHOD" = "docker" ]; then |
| |
| docker-compose down |
| docker tag backgroundfx-pro:previous backgroundfx-pro:$VERSION |
| docker-compose up -d |
| elif [ "$DEPLOY_METHOD" = "kubernetes" ]; then |
| |
| kubectl rollout undo deployment/backgroundfx-pro -n backgroundfx |
| elif [ "$DEPLOY_METHOD" = "server" ]; then |
| |
| 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_deploy_checks() { |
| echo -e "${BLUE}Running pre-deployment checks...${NC}" |
| |
| |
| 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 |
| |
| |
| 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() { |
| 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 |
| |
| |
| pre_deploy_checks |
| |
| |
| create_backup |
| |
| |
| 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 |
| |
| |
| 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 'echo -e "${RED}Deployment failed!${NC}"; exit 1' ERR |
|
|
| |
| main |