Files
michaelschiemer/deployment/scripts/deploy.sh
Michael Schiemer 85e2360a90
All checks were successful
Test Runner / test-basic (push) Successful in 8s
Test Runner / test-php (push) Successful in 7s
Deploy Application / deploy (push) Successful in 1m35s
fix(deploy): improve deployment robustness and reliability
- Add docker volume prune to deploy.sh to prevent stale code issues
- Add automatic migrations and cache warmup to staging entrypoint
- Fix nginx race condition by waiting for PHP-FPM before starting
- Improve PHP healthcheck to use php-fpm-healthcheck
- Add curl to production nginx Dockerfile for healthchecks
- Add ensureSeedsTable() to SeedRepository for automatic table creation
- Update SeedCommand to ensure seeds table exists before operations

This prevents 502 Bad Gateway errors during deployment and ensures
fresh code is deployed without volume cache issues.
2025-11-25 17:44:44 +01:00

196 lines
5.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ==============================================================================
# Application Deployment Script
# ==============================================================================
# Deploys application to staging or production environment
# Usage: ./deploy.sh <environment> [options]
# ==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_info() {
echo -e "${BLUE}${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
print_warning() {
echo -e "${YELLOW}⚠️${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
# Parse arguments
ENVIRONMENT=$1
BUILD_IMAGES=${2:-false}
if [ -z "$ENVIRONMENT" ]; then
print_error "Usage: $0 <environment> [build]"
print_info "Environments: staging, production"
print_info "Options: build - Build Docker images before deployment"
exit 1
fi
if [ "$ENVIRONMENT" != "staging" ] && [ "$ENVIRONMENT" != "production" ]; then
print_error "Invalid environment: $ENVIRONMENT"
print_info "Valid environments: staging, production"
exit 1
fi
# Set compose files
COMPOSE_BASE="docker-compose.base.yml"
if [ "$ENVIRONMENT" = "staging" ]; then
COMPOSE_ENV="docker-compose.staging.yml"
elif [ "$ENVIRONMENT" = "production" ]; then
COMPOSE_ENV="docker-compose.prod.yml"
fi
COMPOSE_FILES="-f $COMPOSE_BASE -f $COMPOSE_ENV"
print_info "Deploying to $ENVIRONMENT environment..."
# Check if secrets exist
SECRETS_DIR="deployment/secrets/$ENVIRONMENT"
if [ ! -d "$SECRETS_DIR" ]; then
print_warning "Secrets directory not found: $SECRETS_DIR"
print_info "Creating secrets directory..."
mkdir -p "$SECRETS_DIR"
fi
MISSING_SECRETS=()
REQUIRED_SECRETS=("db_password.txt" "redis_password.txt" "app_key.txt")
for secret_file in "${REQUIRED_SECRETS[@]}"; do
if [ ! -f "$SECRETS_DIR/$secret_file" ]; then
MISSING_SECRETS+=("$secret_file")
fi
done
if [ ${#MISSING_SECRETS[@]} -gt 0 ]; then
print_error "Missing required secrets:"
for secret in "${MISSING_SECRETS[@]}"; do
print_error " - $SECRETS_DIR/$secret"
done
print_info "See deployment/infrastructure/SECRETS.md for instructions"
exit 1
fi
# Check if infrastructure networks exist
print_info "Checking infrastructure networks..."
if ! docker network ls | grep -q "traefik-public"; then
print_error "traefik-public network not found"
print_info "Please deploy infrastructure stacks first:"
print_info " cd deployment/infrastructure && ./deploy.sh traefik"
exit 1
fi
if ! docker network ls | grep -q "app-internal"; then
print_error "app-internal network not found"
print_info "Please deploy infrastructure stacks first:"
print_info " cd deployment/infrastructure && ./deploy.sh postgresql"
exit 1
fi
# Build images if requested
if [ "$BUILD_IMAGES" = "build" ]; then
print_info "Building Docker images..."
docker compose $COMPOSE_FILES build
fi
# Pull latest images
print_info "Pulling latest images..."
docker compose $COMPOSE_FILES pull || print_warning "Failed to pull some images, continuing..."
# Stop and remove existing containers to prevent name conflicts
print_info "Stopping existing containers..."
docker compose $COMPOSE_FILES down --remove-orphans || print_warning "No existing containers to stop"
# Staging: Remove named volume to ensure fresh code from image
# This prevents stale code persisting between deployments
if [ "$ENVIRONMENT" = "staging" ]; then
print_info "Removing staging code volume to ensure fresh deployment..."
docker volume rm staging-code 2>/dev/null || print_info "No stale staging volume to remove"
fi
# Remove any orphaned containers with conflicting names
for container in nginx php redis scheduler queue-worker; do
if docker ps -a --format '{{.Names}}' | grep -q "^${container}$"; then
print_warning "Removing orphaned container: $container"
docker rm -f "$container" 2>/dev/null || true
fi
done
# Deploy stack
print_info "Deploying application stack..."
docker compose $COMPOSE_FILES up -d --force-recreate --remove-orphans
# Wait for services to be healthy
print_info "Waiting for services to be healthy..."
sleep 10
# Check service status
print_info "Checking service status..."
docker compose $COMPOSE_FILES ps
# Health checks
print_info "Running health checks..."
HEALTH_CHECK_FAILED=0
# Check PHP service
if docker compose $COMPOSE_FILES exec -T php php -v > /dev/null 2>&1; then
print_success "PHP service is healthy"
else
print_error "PHP service health check failed"
HEALTH_CHECK_FAILED=1
fi
# Check Redis service
if docker compose $COMPOSE_FILES exec -T redis redis-cli ping > /dev/null 2>&1; then
print_success "Redis service is healthy"
else
print_error "Redis service health check failed"
HEALTH_CHECK_FAILED=1
fi
# Check Nginx service
if docker compose $COMPOSE_FILES exec -T nginx wget --quiet --tries=1 --spider http://localhost/health > /dev/null 2>&1; then
print_success "Nginx service is healthy"
else
print_warning "Nginx health check endpoint not available (this may be normal)"
fi
if [ $HEALTH_CHECK_FAILED -eq 1 ]; then
print_error "Some health checks failed. Check logs:"
print_info " docker compose $COMPOSE_FILES logs"
exit 1
fi
print_success "Deployment to $ENVIRONMENT completed successfully!"
# Show service URLs
if [ "$ENVIRONMENT" = "production" ]; then
print_info "Application URL: https://michaelschiemer.de"
elif [ "$ENVIRONMENT" = "staging" ]; then
print_info "Application URL: https://staging.michaelschiemer.de"
fi
print_info "View logs: docker compose $COMPOSE_FILES logs -f"
print_info "View status: docker compose $COMPOSE_FILES ps"