| | #!/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 |