- Convert multi-file overlay approach to single docker-compose.yml - Use environment variables for dev/production differences - Remove complex network configuration conflicts - Align with framework principles: simplicity over complexity - Production config via .env.production file Benefits: - No more network subnet conflicts - Single source of truth - Framework-compliant architecture - Easier maintenance and debugging Related: #19 Docker network conflict resolution
176 lines
5.1 KiB
Bash
Executable File
176 lines
5.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Direct Docker-based production deployment
|
|
# Bypasses Ansible for immediate deployment
|
|
|
|
set -euo pipefail
|
|
|
|
SERVER_USER="deploy"
|
|
SERVER_IP="94.16.110.151"
|
|
REMOTE_PATH="/home/deploy/michaelschiemer"
|
|
SSH_OPTS="-o StrictHostKeyChecking=no"
|
|
|
|
# Colors for output
|
|
GREEN="\e[32m"
|
|
YELLOW="\e[33m"
|
|
RED="\e[31m"
|
|
RESET="\e[0m"
|
|
|
|
log_info() {
|
|
echo -e "${YELLOW}[INFO]${RESET} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${RESET} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${RESET} $1"
|
|
}
|
|
|
|
# Check prerequisites
|
|
check_prerequisites() {
|
|
log_info "Checking prerequisites..."
|
|
|
|
if ! ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "echo 'SSH connection successful'" 2>/dev/null; then
|
|
log_error "Cannot connect to production server. Please configure SSH key authentication."
|
|
log_error "Run: ssh-copy-id -i ~/.ssh/production $SERVER_USER@$SERVER_IP"
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
log_error "Docker not found locally. Install Docker first."
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Prerequisites check passed"
|
|
}
|
|
|
|
# Build and push production image
|
|
build_and_push() {
|
|
local image_tag="$(git rev-parse --short HEAD)"
|
|
log_info "Building production image with tag: $image_tag"
|
|
|
|
# Build production image
|
|
docker build -t "michaelschiemer/php-framework:$image_tag" \
|
|
-f docker/php/Dockerfile \
|
|
--target=production \
|
|
--build-arg ENV=production \
|
|
.
|
|
|
|
# Tag as latest for production
|
|
docker tag "michaelschiemer/php-framework:$image_tag" \
|
|
"michaelschiemer/php-framework:production"
|
|
|
|
log_success "Production image built successfully"
|
|
echo "$image_tag"
|
|
}
|
|
|
|
# Deploy to production server
|
|
deploy_to_server() {
|
|
local image_tag="$1"
|
|
|
|
log_info "Deploying to production server..."
|
|
|
|
# Create deployment directory
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "mkdir -p $REMOTE_PATH"
|
|
|
|
# Copy docker-compose files
|
|
scp $SSH_OPTS docker-compose.yml "$SERVER_USER@$SERVER_IP:$REMOTE_PATH/"
|
|
scp $SSH_OPTS deployment/applications/docker-compose.production.yml "$SERVER_USER@$SERVER_IP:$REMOTE_PATH/"
|
|
|
|
# Copy environment file template
|
|
scp $SSH_OPTS .env.production "$SERVER_USER@$SERVER_IP:$REMOTE_PATH/.env" 2>/dev/null || {
|
|
log_info "Creating production environment file..."
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "cat > $REMOTE_PATH/.env << 'EOF'
|
|
APP_ENV=production
|
|
APP_DEBUG=false
|
|
DB_HOST=db
|
|
DB_DATABASE=framework
|
|
DB_USERNAME=framework
|
|
DB_PASSWORD=secure_password_change_me
|
|
REDIS_HOST=redis
|
|
REDIS_PORT=6379
|
|
EOF"
|
|
}
|
|
|
|
# Save Docker image and transfer
|
|
log_info "Transferring Docker image..."
|
|
docker save "michaelschiemer/php-framework:$image_tag" | \
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "docker load"
|
|
|
|
# Deploy with Docker Compose
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
cd $REMOTE_PATH
|
|
|
|
# Stop existing services
|
|
docker compose -f docker-compose.yml -f docker-compose.production.yml down --remove-orphans || true
|
|
|
|
# Start services with production configuration
|
|
IMAGE_TAG=$image_tag docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
|
|
|
|
# Wait for services to be healthy
|
|
sleep 30
|
|
|
|
# Run health check
|
|
if docker compose -f docker-compose.yml -f docker-compose.production.yml ps | grep -q 'healthy\\|Up'; then
|
|
echo 'Deployment successful!'
|
|
else
|
|
echo 'Health check failed!'
|
|
docker compose -f docker-compose.yml -f docker-compose.production.yml logs --tail=50
|
|
exit 1
|
|
fi
|
|
"
|
|
|
|
log_success "Deployment completed successfully!"
|
|
}
|
|
|
|
# Validate deployment
|
|
validate_deployment() {
|
|
log_info "Validating production deployment..."
|
|
|
|
# Test HTTPS endpoint
|
|
if curl -f -k -H "User-Agent: Mozilla/5.0" "https://$SERVER_IP/health" >/dev/null 2>&1; then
|
|
log_success "HTTPS health check passed"
|
|
else
|
|
log_error "HTTPS health check failed"
|
|
return 1
|
|
fi
|
|
|
|
# Check that debug routes are blocked
|
|
local debug_response=$(curl -s -o /dev/null -w '%{http_code}' -k -H "User-Agent: Mozilla/5.0" "https://$SERVER_IP/debug" 2>/dev/null || echo 'connection_failed')
|
|
if [ "$debug_response" = '404' ]; then
|
|
log_success "Debug routes properly blocked"
|
|
else
|
|
log_error "WARNING: Debug routes not properly blocked (got: $debug_response)"
|
|
fi
|
|
|
|
log_success "Deployment validation completed"
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
log_info "Starting direct production deployment..."
|
|
|
|
# Check prerequisites
|
|
check_prerequisites
|
|
|
|
# Build and get image tag
|
|
local image_tag
|
|
image_tag=$(build_and_push)
|
|
|
|
# Deploy to server
|
|
deploy_to_server "$image_tag"
|
|
|
|
# Validate deployment
|
|
validate_deployment
|
|
|
|
log_success "Production deployment completed successfully!"
|
|
log_info "Application available at: https://michaelschiemer.de"
|
|
log_info "Deployed commit: $(git rev-parse HEAD)"
|
|
}
|
|
|
|
# Execute if run directly
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi |