Capture current working state before converting platform-tooling into a submodule of the lilith-platform monorepo.
317 lines
9.4 KiB
Bash
Executable file
317 lines
9.4 KiB
Bash
Executable file
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
#
|
|
# Production Deployment Script - lilith-platform
|
|
#
|
|
# Deploys webmap-router and application services to nasty.sh VPS
|
|
#
|
|
# Architecture:
|
|
# - Uses shared lib/ modules for SOLID/DRY compliance
|
|
# - OS-agnostic deployment
|
|
#
|
|
# Prerequisites:
|
|
# - VPN configured between apricot (10.9.0.1) and VPS (10.9.0.2)
|
|
# - PostgreSQL/Redis/ML running on apricot
|
|
# - SSH access to VPS
|
|
# - Docker images built
|
|
#
|
|
# Usage: ./deploy-prod.sh [--build | --deploy | --full]
|
|
#
|
|
|
|
# =============================================================================
|
|
# INITIALIZATION
|
|
# =============================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
export SCRIPT_LIB_DIR="${SCRIPT_DIR}/../lib"
|
|
|
|
# Load shared libraries
|
|
source "${SCRIPT_LIB_DIR}/colors.sh"
|
|
source "${SCRIPT_LIB_DIR}/logger.sh"
|
|
source "${SCRIPT_LIB_DIR}/config.sh"
|
|
|
|
# Initialize logging
|
|
log_init "DEPLOY"
|
|
|
|
# Initialize configuration
|
|
config_init "$SCRIPT_DIR/.."
|
|
|
|
# Deployment configuration
|
|
DEPLOY_PATH="/opt/lilith-platform"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
|
|
# =============================================================================
|
|
# PREREQUISITE CHECKS
|
|
# =============================================================================
|
|
|
|
check_prerequisites() {
|
|
log_step "Checking prerequisites..."
|
|
|
|
# Check commands
|
|
local required_cmds=("docker" "pnpm" "rsync" "ssh")
|
|
for cmd in "${required_cmds[@]}"; do
|
|
if ! command -v "$cmd" &>/dev/null; then
|
|
log_error "$cmd not installed"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# Check VPS connectivity
|
|
local ssh_cmd
|
|
ssh_cmd=$(config_get_ssh_cmd "$CONFIG_VPS_HOST" "$CONFIG_VPS_USER")
|
|
|
|
if ! $ssh_cmd "echo connected" &>/dev/null; then
|
|
log_error "Cannot connect to VPS at $CONFIG_VPS_HOST"
|
|
exit 1
|
|
fi
|
|
|
|
# Check VPN connectivity from VPS to apricot
|
|
log_info "Checking VPN connectivity..."
|
|
if ! $ssh_cmd "ping -c 1 -W 2 $CONFIG_VPN_LOCAL_IP >/dev/null 2>&1"; then
|
|
log_warn "VPN may not be configured - VPS cannot reach apricot ($CONFIG_VPN_LOCAL_IP)"
|
|
log_warn "See: infrastructure/VPN_SETUP.md"
|
|
read -p "Continue anyway? (y/N) " -n 1 -r
|
|
echo
|
|
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
|
else
|
|
log_success "VPN connectivity verified"
|
|
fi
|
|
|
|
log_success "Prerequisites satisfied"
|
|
}
|
|
|
|
# =============================================================================
|
|
# BUILD IMAGES
|
|
# =============================================================================
|
|
|
|
build_images() {
|
|
log_step "Building Docker images..."
|
|
|
|
cd "$PROJECT_ROOT"
|
|
|
|
# Build apps first
|
|
log_info "Building frontend apps..."
|
|
pnpm build
|
|
|
|
# Build webmap-router image
|
|
log_info "Building webmap-router image..."
|
|
docker build -t lilith-platform-webmap-router:latest \
|
|
-f @services/webmap-router/Dockerfile \
|
|
.
|
|
|
|
# Build platform-service image
|
|
log_info "Building platform-service image..."
|
|
docker build -t lilith-platform-platform:latest \
|
|
-f @services/platform/Dockerfile \
|
|
.
|
|
|
|
# Build drive-service image
|
|
log_info "Building drive-service image..."
|
|
docker build -t lilith-platform-drive:latest \
|
|
-f @services/drive/Dockerfile \
|
|
.
|
|
|
|
log_success "All images built"
|
|
}
|
|
|
|
# =============================================================================
|
|
# DEPLOY TO VPS
|
|
# =============================================================================
|
|
|
|
deploy_to_vps() {
|
|
log_step "Deploying to VPS..."
|
|
|
|
local ssh_cmd
|
|
ssh_cmd=$(config_get_ssh_cmd "$CONFIG_VPS_HOST" "$CONFIG_VPS_USER")
|
|
|
|
# Create deployment directory
|
|
log_info "Creating deployment directory on VPS..."
|
|
$ssh_cmd "mkdir -p $DEPLOY_PATH"
|
|
|
|
# Upload docker-compose and configs
|
|
log_info "Uploading configuration files..."
|
|
rsync -avz --delete \
|
|
"$PROJECT_ROOT/infrastructure/" \
|
|
"${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:${DEPLOY_PATH}/infrastructure/"
|
|
|
|
# Upload built apps
|
|
log_info "Uploading built apps..."
|
|
rsync -avz --delete \
|
|
"$PROJECT_ROOT/features/" \
|
|
"${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:${DEPLOY_PATH}/features/"
|
|
|
|
# Upload .env if exists
|
|
if [ -f "$PROJECT_ROOT/infrastructure/env/.env.prod" ]; then
|
|
log_info "Uploading production environment file..."
|
|
scp "$PROJECT_ROOT/infrastructure/env/.env.prod" \
|
|
"${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:${DEPLOY_PATH}/.env"
|
|
else
|
|
log_warn "No .env.prod file found - you'll need to configure manually"
|
|
fi
|
|
|
|
# Upload images (save + load approach)
|
|
log_info "Saving Docker images..."
|
|
docker save \
|
|
lilith-platform-webmap-router:latest \
|
|
lilith-platform-platform:latest \
|
|
lilith-platform-drive:latest \
|
|
| gzip > /tmp/lilith-images.tar.gz
|
|
|
|
log_info "Uploading Docker images to VPS..."
|
|
scp /tmp/lilith-images.tar.gz "${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:/tmp/"
|
|
|
|
log_info "Loading Docker images on VPS..."
|
|
$ssh_cmd "gunzip -c /tmp/lilith-images.tar.gz | docker load"
|
|
|
|
# Clean up temp file
|
|
rm /tmp/lilith-images.tar.gz
|
|
|
|
log_success "Deployment files uploaded"
|
|
}
|
|
|
|
# =============================================================================
|
|
# START SERVICES
|
|
# =============================================================================
|
|
|
|
start_services() {
|
|
log_step "Starting services on VPS..."
|
|
|
|
local ssh_cmd
|
|
ssh_cmd=$(config_get_ssh_cmd "$CONFIG_VPS_HOST" "$CONFIG_VPS_USER")
|
|
|
|
$ssh_cmd "cd $DEPLOY_PATH && docker compose -f infrastructure/docker/docker-compose.prod.yml up -d"
|
|
|
|
log_info "Waiting for services to start..."
|
|
sleep 10
|
|
|
|
# Check service health
|
|
log_info "Checking service health..."
|
|
$ssh_cmd "cd $DEPLOY_PATH && docker compose -f infrastructure/docker/docker-compose.prod.yml ps"
|
|
|
|
log_success "Services started"
|
|
}
|
|
|
|
# =============================================================================
|
|
# CONFIGURE NGINX
|
|
# =============================================================================
|
|
|
|
configure_nginx() {
|
|
log_step "Configuring Nginx..."
|
|
|
|
local ssh_cmd
|
|
ssh_cmd=$(config_get_ssh_cmd "$CONFIG_VPS_HOST" "$CONFIG_VPS_USER")
|
|
|
|
# Copy Nginx configs
|
|
log_info "Uploading Nginx configuration..."
|
|
$ssh_cmd "mkdir -p /etc/nginx/conf.d /etc/nginx/snippets"
|
|
|
|
rsync -avz \
|
|
"$PROJECT_ROOT/infrastructure/nginx/conf.d/" \
|
|
"${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:/etc/nginx/conf.d/"
|
|
|
|
rsync -avz \
|
|
"$PROJECT_ROOT/infrastructure/nginx/snippets/" \
|
|
"${CONFIG_VPS_USER}@${CONFIG_VPS_HOST}:/etc/nginx/snippets/"
|
|
|
|
# Test Nginx config
|
|
log_info "Testing Nginx configuration..."
|
|
$ssh_cmd "nginx -t"
|
|
|
|
# Reload Nginx
|
|
log_info "Reloading Nginx..."
|
|
$ssh_cmd "systemctl reload nginx"
|
|
|
|
log_success "Nginx configured"
|
|
}
|
|
|
|
# =============================================================================
|
|
# VERIFY DEPLOYMENT
|
|
# =============================================================================
|
|
|
|
verify_deployment() {
|
|
log_step "Verifying deployment..."
|
|
|
|
local ssh_cmd
|
|
ssh_cmd=$(config_get_ssh_cmd "$CONFIG_VPS_HOST" "$CONFIG_VPS_USER")
|
|
|
|
# Test webmap-router health
|
|
log_info "Testing webmap-router..."
|
|
if $ssh_cmd "curl -f http://localhost:4002/health" &>/dev/null; then
|
|
log_success "webmap-router responding"
|
|
else
|
|
log_error "webmap-router not responding"
|
|
fi
|
|
|
|
# Test platform-service health
|
|
log_info "Testing platform-service..."
|
|
if $ssh_cmd "curl -f http://localhost:4000/api/health" &>/dev/null; then
|
|
log_success "platform-service responding"
|
|
else
|
|
log_error "platform-service not responding"
|
|
fi
|
|
|
|
log_info "Deployment verification complete!"
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN DEPLOYMENT WORKFLOW
|
|
# =============================================================================
|
|
|
|
main() {
|
|
local MODE="${1:---full}"
|
|
|
|
log_banner "lilith-platform Production Deployment"
|
|
|
|
echo ""
|
|
log_info "VPS: $CONFIG_VPS_HOST"
|
|
log_info "Database: apricot ($CONFIG_VPN_LOCAL_IP) via VPN"
|
|
echo ""
|
|
|
|
case "$MODE" in
|
|
--build)
|
|
check_prerequisites
|
|
build_images
|
|
;;
|
|
--deploy)
|
|
check_prerequisites
|
|
deploy_to_vps
|
|
start_services
|
|
configure_nginx
|
|
verify_deployment
|
|
;;
|
|
--full)
|
|
check_prerequisites
|
|
build_images
|
|
deploy_to_vps
|
|
start_services
|
|
configure_nginx
|
|
verify_deployment
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: $0 [--build | --deploy | --full]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --build Build Docker images only"
|
|
echo " --deploy Deploy to VPS (assumes images built)"
|
|
echo " --full Build and deploy (default)"
|
|
exit 0
|
|
;;
|
|
*)
|
|
log_error "Unknown mode: $MODE"
|
|
log_error "Usage: $0 [--build | --deploy | --full]"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
log_info ""
|
|
log_success "🎉 Deployment complete!"
|
|
log_info ""
|
|
log_info "Next steps:"
|
|
log_info " 1. Run Stage 1 database migration"
|
|
log_info " 2. Configure SSL certificates"
|
|
log_info " 3. Test domains in browser"
|
|
log_info " 4. Monitor logs: ssh $CONFIG_VPS_HOST 'docker logs -f lilith-platform-prod-webmap-router'"
|
|
}
|
|
|
|
main "$@"
|