|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #!/bin/bash
-
- # RAGFlow Data Migration Script
- # Usage: ./migration.sh [backup|restore] [backup_folder]
- #
- # This script helps you backup and restore RAGFlow Docker volumes
- # including MySQL, MinIO, Redis, and Elasticsearch data.
-
- set -e # Exit on any error
- # Instead, we'll handle errors manually for better debugging experience
-
- # Default values
- DEFAULT_BACKUP_FOLDER="backup"
- VOLUMES=("docker_mysql_data" "docker_minio_data" "docker_redis_data" "docker_esdata01")
- BACKUP_FILES=("mysql_backup.tar.gz" "minio_backup.tar.gz" "redis_backup.tar.gz" "es_backup.tar.gz")
-
- # Function to display help information
- show_help() {
- echo "RAGFlow Data Migration Tool"
- echo ""
- echo "USAGE:"
- echo " $0 <operation> [backup_folder]"
- echo ""
- echo "OPERATIONS:"
- echo " backup - Create backup of all RAGFlow data volumes"
- echo " restore - Restore RAGFlow data volumes from backup"
- echo " help - Show this help message"
- echo ""
- echo "PARAMETERS:"
- echo " backup_folder - Name of backup folder (default: '$DEFAULT_BACKUP_FOLDER')"
- echo ""
- echo "EXAMPLES:"
- echo " $0 backup # Backup to './backup' folder"
- echo " $0 backup my_backup # Backup to './my_backup' folder"
- echo " $0 restore # Restore from './backup' folder"
- echo " $0 restore my_backup # Restore from './my_backup' folder"
- echo ""
- echo "DOCKER VOLUMES:"
- echo " - docker_mysql_data (MySQL database)"
- echo " - docker_minio_data (MinIO object storage)"
- echo " - docker_redis_data (Redis cache)"
- echo " - docker_esdata01 (Elasticsearch indices)"
- }
-
- # Function to check if Docker is running
- check_docker() {
- if ! docker info >/dev/null 2>&1; then
- echo "❌ Error: Docker is not running or not accessible"
- echo "Please start Docker and try again"
- exit 1
- fi
- }
-
- # Function to check if volume exists
- volume_exists() {
- local volume_name=$1
- docker volume inspect "$volume_name" >/dev/null 2>&1
- }
-
- # Function to check if any containers are using the target volumes
- check_containers_using_volumes() {
- echo "🔍 Checking for running containers that might be using target volumes..."
-
- # Get all running containers
- local running_containers=$(docker ps --format "{{.Names}}")
-
- if [ -z "$running_containers" ]; then
- echo "✅ No running containers found"
- return 0
- fi
-
- # Check each running container for volume usage
- local containers_using_volumes=()
- local volume_usage_details=()
-
- for container in $running_containers; do
- # Get container's mount information
- local mounts=$(docker inspect "$container" --format '{{range .Mounts}}{{.Source}}{{"|"}}{{end}}' 2>/dev/null || echo "")
-
- # Check if any of our target volumes are used by this container
- for volume in "${VOLUMES[@]}"; do
- if echo "$mounts" | grep -q "$volume"; then
- containers_using_volumes+=("$container")
- volume_usage_details+=("$container -> $volume")
- break
- fi
- done
- done
-
- # If any containers are using our volumes, show error and exit
- if [ ${#containers_using_volumes[@]} -gt 0 ]; then
- echo ""
- echo "❌ ERROR: Found running containers using target volumes!"
- echo ""
- echo "📋 Running containers status:"
- docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
- echo ""
- echo "🔗 Volume usage details:"
- for detail in "${volume_usage_details[@]}"; do
- echo " - $detail"
- done
- echo ""
- echo "🛑 SOLUTION: Stop the containers before performing backup/restore operations:"
- echo " docker-compose -f docker/<your-docker-compose-file>.yml down"
- echo ""
- echo "💡 After backup/restore, you can restart with:"
- echo " docker-compose -f docker/<your-docker-compose-file>.yml up -d"
- echo ""
- exit 1
- fi
-
- echo "✅ No containers are using target volumes, safe to proceed"
- return 0
- }
-
- # Function to confirm user action
- confirm_action() {
- local message=$1
- echo -n "$message (y/N): "
- read -r response
- case "$response" in
- [yY]|[yY][eE][sS]) return 0 ;;
- *) return 1 ;;
- esac
- }
-
- # Function to perform backup
- perform_backup() {
- local backup_folder=$1
-
- echo "🚀 Starting RAGFlow data backup..."
- echo "📁 Backup folder: $backup_folder"
- echo ""
-
- # Check if any containers are using the volumes
- check_containers_using_volumes
-
- # Create backup folder if it doesn't exist
- mkdir -p "$backup_folder"
-
- # Backup each volume
- for i in "${!VOLUMES[@]}"; do
- local volume="${VOLUMES[$i]}"
- local backup_file="${BACKUP_FILES[$i]}"
- local step=$((i + 1))
-
- echo "📦 Step $step/4: Backing up $volume..."
-
- if volume_exists "$volume"; then
- docker run --rm \
- -v "$volume":/source \
- -v "$(pwd)/$backup_folder":/backup \
- alpine tar czf "/backup/$backup_file" -C /source .
- echo "✅ Successfully backed up $volume to $backup_folder/$backup_file"
- else
- echo "⚠️ Warning: Volume $volume does not exist, skipping..."
- fi
- echo ""
- done
-
- echo "🎉 Backup completed successfully!"
- echo "📍 Backup location: $(pwd)/$backup_folder"
-
- # List backup files with sizes
- echo ""
- echo "📋 Backup files created:"
- for backup_file in "${BACKUP_FILES[@]}"; do
- if [ -f "$backup_folder/$backup_file" ]; then
- local size=$(ls -lh "$backup_folder/$backup_file" | awk '{print $5}')
- echo " - $backup_file ($size)"
- fi
- done
- }
-
- # Function to perform restore
- perform_restore() {
- local backup_folder=$1
-
- echo "🔄 Starting RAGFlow data restore..."
- echo "📁 Backup folder: $backup_folder"
- echo ""
-
- # Check if any containers are using the volumes
- check_containers_using_volumes
-
- # Check if backup folder exists
- if [ ! -d "$backup_folder" ]; then
- echo "❌ Error: Backup folder '$backup_folder' does not exist"
- exit 1
- fi
-
- # Check if all backup files exist
- local missing_files=()
- for backup_file in "${BACKUP_FILES[@]}"; do
- if [ ! -f "$backup_folder/$backup_file" ]; then
- missing_files+=("$backup_file")
- fi
- done
-
- if [ ${#missing_files[@]} -gt 0 ]; then
- echo "❌ Error: Missing backup files:"
- for file in "${missing_files[@]}"; do
- echo " - $file"
- done
- echo "Please ensure all backup files are present in '$backup_folder'"
- exit 1
- fi
-
- # Check for existing volumes and warn user
- local existing_volumes=()
- for volume in "${VOLUMES[@]}"; do
- if volume_exists "$volume"; then
- existing_volumes+=("$volume")
- fi
- done
-
- if [ ${#existing_volumes[@]} -gt 0 ]; then
- echo "⚠️ WARNING: The following Docker volumes already exist:"
- for volume in "${existing_volumes[@]}"; do
- echo " - $volume"
- done
- echo ""
- echo "🔴 IMPORTANT: Restoring will OVERWRITE existing data!"
- echo "💡 Recommendation: Create a backup of your current data first:"
- echo " $0 backup current_backup_$(date +%Y%m%d_%H%M%S)"
- echo ""
-
- if ! confirm_action "Do you want to continue with the restore operation?"; then
- echo "❌ Restore operation cancelled by user"
- exit 0
- fi
- fi
-
- # Create volumes and restore data
- for i in "${!VOLUMES[@]}"; do
- local volume="${VOLUMES[$i]}"
- local backup_file="${BACKUP_FILES[$i]}"
- local step=$((i + 1))
-
- echo "🔧 Step $step/4: Restoring $volume..."
-
- # Create volume if it doesn't exist
- if ! volume_exists "$volume"; then
- echo " 📋 Creating Docker volume: $volume"
- docker volume create "$volume"
- else
- echo " 📋 Using existing Docker volume: $volume"
- fi
-
- # Restore data
- echo " 📥 Restoring data from $backup_file..."
- docker run --rm \
- -v "$volume":/target \
- -v "$(pwd)/$backup_folder":/backup \
- alpine tar xzf "/backup/$backup_file" -C /target
-
- echo "✅ Successfully restored $volume"
- echo ""
- done
-
- echo "🎉 Restore completed successfully!"
- echo "💡 You can now start your RAGFlow services"
- }
-
- # Main script logic
- main() {
- # Check if Docker is available
- check_docker
-
- # Parse command line arguments
- local operation=${1:-}
- local backup_folder=${2:-$DEFAULT_BACKUP_FOLDER}
-
- # Handle help or no arguments
- if [ -z "$operation" ] || [ "$operation" = "help" ] || [ "$operation" = "-h" ] || [ "$operation" = "--help" ]; then
- show_help
- exit 0
- fi
-
- # Validate operation
- case "$operation" in
- backup)
- perform_backup "$backup_folder"
- ;;
- restore)
- perform_restore "$backup_folder"
- ;;
- *)
- echo "❌ Error: Invalid operation '$operation'"
- echo ""
- show_help
- exit 1
- ;;
- esac
- }
-
- # Run main function with all arguments
- main "$@"
|