Files
michaelschiemer/deployment/scripts/deploy-staging.sh
2025-11-24 21:28:25 +01:00

236 lines
7.4 KiB
Bash
Executable File

#!/bin/bash
set -e
# ============================================================================
# Staging Deployment Script
# ============================================================================
# Based on .gitea/workflows/deploy-staging.yml
# Deploys to staging environment at staging.michaelschiemer.de
# ============================================================================
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
REGISTRY="${REGISTRY:-localhost:5000}"
IMAGE_NAME="${IMAGE_NAME:-framework}"
IMAGE_TAG="${IMAGE_TAG:-staging}"
COMPOSE_PROJECT_NAME="framework-staging"
# Remote server configuration (from environment or defaults)
REMOTE_USER="${STAGING_USER:-deploy}"
REMOTE_HOST="${STAGING_HOST:-staging.michaelschiemer.de}"
REMOTE_PORT="${STAGING_SSH_PORT:-22}"
REMOTE_PATH="/opt/framework-staging"
# Validation
if [ -z "$REMOTE_HOST" ]; then
echo -e "${RED}❌ Error: STAGING_HOST environment variable is required${NC}"
echo "Export STAGING_HOST before running this script:"
echo " export STAGING_HOST=staging.michaelschiemer.de"
exit 1
fi
echo "=================================================="
echo "🚀 Starting Staging Deployment"
echo "=================================================="
echo "Registry: ${REGISTRY}"
echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"
echo "Remote: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}"
echo "Path: ${REMOTE_PATH}"
echo ""
# Step 1: Build Docker image
echo -e "${GREEN}[1/7] Building Docker image...${NC}"
docker build \
--file docker/php/Dockerfile \
--tag "${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" \
--build-arg ENV=staging \
--build-arg COMPOSER_INSTALL_FLAGS="--no-dev --optimize-autoloader --no-interaction" \
.
if [ $? -ne 0 ]; then
echo -e "${RED}❌ Docker build failed${NC}"
exit 1
fi
# Step 2: Push image to registry
echo -e "${GREEN}[2/7] Pushing image to registry...${NC}"
docker push "${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ Docker push failed${NC}"
exit 1
fi
# Step 3: Prepare deployment files
echo -e "${GREEN}[3/7] Preparing deployment files...${NC}"
rm -rf deployment-staging-tmp
mkdir -p deployment-staging-tmp
cp docker-compose.base.yml deployment-staging-tmp/
cp docker-compose.staging.yml deployment-staging-tmp/
cp -r docker deployment-staging-tmp/
# Create deployment script
cat > deployment-staging-tmp/deploy.sh << 'DEPLOY_SCRIPT'
#!/bin/bash
set -e
echo "=================================================="
echo "Starting Staging Deployment on Server"
echo "=================================================="
echo ""
# Pull latest images
echo "[1/5] Pulling latest Docker images..."
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml pull
# Stop existing containers
echo "[2/5] Stopping existing containers..."
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml down
# Start new containers
echo "[3/5] Starting new containers..."
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml up -d
# Wait for services to be healthy
echo "[4/5] Waiting for services to be healthy..."
sleep 10
# Verify health
echo "[5/5] Verifying deployment..."
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml ps
echo ""
echo "=================================================="
echo "✅ Staging Deployment Complete"
echo "=================================================="
DEPLOY_SCRIPT
chmod +x deployment-staging-tmp/deploy.sh
# Step 4: Create remote directory and backup
echo -e "${GREEN}[4/7] Creating remote directory and backup...${NC}"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "
mkdir -p ${REMOTE_PATH}
cd ${REMOTE_PATH}
# Backup current deployment
if [ -d 'current' ]; then
echo 'Backing up current deployment...'
timestamp=\$(date +%Y%m%d_%H%M%S)
mv current backup_\${timestamp}
# Keep only last 5 backups
ls -dt backup_* 2>/dev/null | tail -n +6 | xargs rm -rf 2>/dev/null || true
echo 'Backup created: backup_'\${timestamp}
fi
# Create new deployment directory
mkdir -p current
"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ SSH connection or remote directory creation failed${NC}"
rm -rf deployment-staging-tmp
exit 1
fi
# Step 5: Copy deployment files to server
echo -e "${GREEN}[5/7] Copying deployment files to server...${NC}"
scp -P "${REMOTE_PORT}" -r deployment-staging-tmp/* "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/current/"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ SCP file transfer failed${NC}"
rm -rf deployment-staging-tmp
exit 1
fi
# Cleanup local temp directory
rm -rf deployment-staging-tmp
# Step 6: Execute deployment on server
echo -e "${GREEN}[6/7] Executing deployment on server...${NC}"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "
cd ${REMOTE_PATH}/current
./deploy.sh
"
if [ $? -ne 0 ]; then
echo -e "${RED}❌ Deployment execution failed${NC}"
echo -e "${YELLOW}⚠️ Attempting automatic rollback...${NC}"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "
cd ${REMOTE_PATH}
if [ -d \"\$(ls -dt backup_* 2>/dev/null | head -n1)\" ]; then
echo 'Rolling back to previous deployment...'
latest_backup=\$(ls -dt backup_* | head -n1)
# Stop current broken deployment
cd current
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml down 2>/dev/null || true
cd ..
# Restore backup
rm -rf current
cp -r \"\$latest_backup\" current
# Start restored deployment
cd current
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml up -d
echo '✅ Rollback complete!'
else
echo '❌ No backup available for rollback'
fi
"
exit 1
fi
# Step 7: Health check
echo -e "${GREEN}[7/7] Performing health checks...${NC}"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "
cd ${REMOTE_PATH}/current
# Wait for services to be fully ready
echo 'Waiting 30 seconds for services to initialize...'
sleep 30
# Check container status
echo 'Checking container status...'
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml ps
# Check service health
echo 'Checking service health...'
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml exec -T staging-app php -v || echo 'PHP health check skipped'
# Test HTTP endpoint (via internal network)
echo 'Testing HTTP endpoint...'
docker-compose -f docker-compose.base.yml -f docker-compose.staging.yml exec -T staging-nginx wget -q -O- http://localhost/health || echo 'Health check endpoint not yet available'
echo ''
echo '✅ Health check complete!'
"
if [ $? -ne 0 ]; then
echo -e "${YELLOW}⚠️ Health check had issues but deployment may still be functional${NC}"
fi
echo ""
echo "=================================================="
echo -e "${GREEN}✅ Staging Deployment Successful${NC}"
echo "=================================================="
echo "URL: https://staging.michaelschiemer.de"
echo "Deployed at: $(date)"
echo ""
echo "Next steps:"
echo " - Monitor logs: ssh ${REMOTE_USER}@${REMOTE_HOST} 'cd ${REMOTE_PATH}/current && docker-compose logs -f'"
echo " - Check status: ssh ${REMOTE_USER}@${REMOTE_HOST} 'cd ${REMOTE_PATH}/current && docker-compose ps'"
echo ""