#!/bin/bash # Basil Deployment Script # This script pulls the latest Docker images and restarts the containers set -e # Exit on error # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # Load environment variables from .env file if it exists if [ -f "$PROJECT_DIR/.env" ]; then set -a # automatically export all variables source "$PROJECT_DIR/.env" set +a fi LOG_FILE="$PROJECT_DIR/deploy.log" BACKUP_DIR="$PROJECT_DIR/backups" DOCKER_REGISTRY="${DOCKER_REGISTRY:-harbor.pkartchner.com}" DOCKER_USERNAME="${DOCKER_USERNAME}" IMAGE_TAG="${IMAGE_TAG:-latest}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Logging function log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" } warning() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE" } # Check if Docker is running check_docker() { if ! docker info > /dev/null 2>&1; then error "Docker is not running. Please start Docker and try again." exit 1 fi log "Docker is running" } # Login to Harbor registry login_to_harbor() { log "Logging in to Harbor registry..." if [ -z "$HARBOR_PASSWORD" ]; then error "HARBOR_PASSWORD environment variable not set" exit 1 fi echo "$HARBOR_PASSWORD" | docker login "$DOCKER_REGISTRY" \ --username "robot\$${DOCKER_USERNAME}+basil-cicd" \ --password-stdin || { error "Failed to login to Harbor" exit 1 } log "Successfully logged in to Harbor" } # Create backup before deployment create_backup() { log "Creating pre-deployment backup..." # Ensure backup directory exists mkdir -p "$BACKUP_DIR" # Note: Automatic API backup is skipped because port 3001 is not exposed to localhost # To create a backup manually, use: docker exec basil-api npm run backup log "Skipping automatic backup (API port not exposed to host)" log "Manual backup command: docker exec basil-api npm run backup" } # Pull latest images from registry pull_images() { log "Pulling latest Docker images..." if [ -z "$DOCKER_USERNAME" ]; then error "DOCKER_USERNAME environment variable not set" exit 1 fi # Pull API image log "Pulling API image: ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/basil-api:${IMAGE_TAG}" docker pull "${DOCKER_REGISTRY}/${DOCKER_USERNAME}/basil-api:${IMAGE_TAG}" || { error "Failed to pull API image" exit 1 } # Pull Web image log "Pulling Web image: ${DOCKER_REGISTRY}/${DOCKER_USERNAME}/basil-web:${IMAGE_TAG}" docker pull "${DOCKER_REGISTRY}/${DOCKER_USERNAME}/basil-web:${IMAGE_TAG}" || { error "Failed to pull Web image" exit 1 } log "Successfully pulled all images" } # Update docker-compose.yml to use registry images update_docker_compose() { log "Updating docker-compose configuration..." # Create docker-compose.override.yml to use registry images cat > "$PROJECT_DIR/docker-compose.override.yml" <&1 | grep -q "Basil API server running"; then log "API has finished initialization" break fi RETRY_COUNT=$((RETRY_COUNT + 1)) if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then warning "API startup message not detected after $MAX_RETRIES attempts" log "API container is running, continuing anyway..." break fi sleep 2 done log "All health checks passed" } # Cleanup old images cleanup_old_images() { log "Cleaning up old Docker images..." docker image prune -f > /dev/null 2>&1 || warning "Failed to prune some images" log "Cleanup complete" } # Main deployment flow main() { log "=========================================" log "Starting Basil deployment" log "Registry: ${DOCKER_REGISTRY}" log "Username: ${DOCKER_USERNAME}" log "Tag: ${IMAGE_TAG}" log "=========================================" check_docker login_to_harbor create_backup pull_images run_migrations update_docker_compose restart_containers health_check cleanup_old_images log "=========================================" log "Deployment completed successfully!" log "=========================================" } # Run main function main "$@"