#!/bin/bash # ============================================================================= # Document Server - Synology 업데이트 스크립트 # Git을 통한 무중단 업데이트 및 롤백 지원 # ============================================================================= set -e # 색상 정의 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 로그 함수 log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # 환경 설정 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" COMPOSE_FILE="docker-compose.synology.yml" BACKUP_DIR="/volume2/document-storage/backups" UPDATE_LOG="/volume1/docker/document-server/logs/update.log" # 업데이트 모드 설정 UPDATE_MODE="${1:-safe}" # safe, force, rollback log_info "🔄 Document Server 업데이트 시작 (모드: $UPDATE_MODE)" echo "$(date '+%Y-%m-%d %H:%M:%S') - 업데이트 시작: $UPDATE_MODE" >> "$UPDATE_LOG" cd "$PROJECT_DIR" # 현재 상태 확인 log_info "📊 현재 상태 확인 중..." # Git 상태 확인 if [ ! -d ".git" ]; then log_error "Git 저장소가 아닙니다. Git 클론으로 설치해주세요." exit 1 fi # 현재 커밋 해시 저장 (롤백용) CURRENT_COMMIT=$(git rev-parse HEAD) CURRENT_BRANCH=$(git branch --show-current) echo "이전 커밋: $CURRENT_COMMIT" >> "$UPDATE_LOG" log_info "현재 브랜치: $CURRENT_BRANCH" log_info "현재 커밋: ${CURRENT_COMMIT:0:8}" # 컨테이너 상태 확인 if docker-compose -f "$COMPOSE_FILE" ps -q | grep -q .; then CONTAINERS_RUNNING=true log_info "컨테이너가 실행 중입니다" else CONTAINERS_RUNNING=false log_warning "컨테이너가 실행 중이지 않습니다" fi # 롤백 모드 if [ "$UPDATE_MODE" = "rollback" ]; then log_warning "🔙 롤백 모드 실행" # 마지막 성공한 커밋으로 롤백 LAST_SUCCESS=$(tail -n 20 "$UPDATE_LOG" | grep "업데이트 성공" | tail -n 1 | awk '{print $6}') if [ -z "$LAST_SUCCESS" ]; then log_error "롤백할 커밋을 찾을 수 없습니다" exit 1 fi log_info "롤백 대상 커밋: $LAST_SUCCESS" # 롤백 실행 git reset --hard "$LAST_SUCCESS" # 컨테이너 재시작 if [ "$CONTAINERS_RUNNING" = true ]; then log_info "컨테이너 재시작 중..." docker-compose -f "$COMPOSE_FILE" down docker-compose -f "$COMPOSE_FILE" up -d --build fi log_success "롤백 완료: $LAST_SUCCESS" echo "$(date '+%Y-%m-%d %H:%M:%S') - 롤백 완료: $LAST_SUCCESS" >> "$UPDATE_LOG" exit 0 fi # 업데이트 가능 여부 확인 log_info "🔍 업데이트 확인 중..." # 원격 저장소에서 최신 정보 가져오기 git fetch origin # 업데이트 가능한 커밋 수 확인 COMMITS_BEHIND=$(git rev-list --count HEAD..origin/$CURRENT_BRANCH) if [ "$COMMITS_BEHIND" -eq 0 ]; then log_success "이미 최신 버전입니다" exit 0 fi log_info "업데이트 가능한 커밋: $COMMITS_BEHIND개" # 변경사항 미리보기 log_info "📝 변경사항 미리보기:" git log --oneline HEAD..origin/$CURRENT_BRANCH | head -10 # Safe 모드에서 사용자 확인 if [ "$UPDATE_MODE" = "safe" ]; then echo "" read -p "업데이트를 진행하시겠습니까? (y/N): " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "업데이트가 취소되었습니다" exit 0 fi fi # 백업 생성 log_info "💾 백업 생성 중..." BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_NAME="pre_update_${BACKUP_TIMESTAMP}" # 데이터베이스 백업 if [ "$CONTAINERS_RUNNING" = true ]; then docker-compose -f "$COMPOSE_FILE" exec -T database pg_dump -U docuser document_db > "$BACKUP_DIR/db_${BACKUP_NAME}.sql" log_success "데이터베이스 백업 완료" fi # 설정 파일 백업 tar -czf "$BACKUP_DIR/config_${BACKUP_NAME}.tar.gz" \ /volume1/docker/document-server/config/ \ .env.synology 2>/dev/null || true log_success "설정 파일 백업 완료" # Git 업데이트 실행 log_info "📥 코드 업데이트 중..." # 로컬 변경사항 임시 저장 (있는 경우) if ! git diff --quiet; then log_warning "로컬 변경사항을 임시 저장합니다" git stash push -m "Auto-stash before update $BACKUP_TIMESTAMP" fi # 업데이트 실행 git pull origin "$CURRENT_BRANCH" NEW_COMMIT=$(git rev-parse HEAD) log_success "코드 업데이트 완료: ${NEW_COMMIT:0:8}" # Docker 이미지 업데이트 확인 log_info "🐳 Docker 이미지 업데이트 확인 중..." # Dockerfile이나 requirements.txt 변경 확인 NEED_REBUILD=false if git diff --name-only "$CURRENT_COMMIT" "$NEW_COMMIT" | grep -E "(Dockerfile|requirements.txt|pyproject.toml|package.json)" > /dev/null; then NEED_REBUILD=true log_info "의존성 변경 감지 - 이미지 재빌드 필요" fi # 컨테이너 업데이트 if [ "$CONTAINERS_RUNNING" = true ]; then log_info "🔄 서비스 업데이트 중..." if [ "$NEED_REBUILD" = true ]; then log_info "이미지 재빌드 중..." # 무중단 업데이트를 위한 단계별 재시작 docker-compose -f "$COMPOSE_FILE" build --no-cache backend docker-compose -f "$COMPOSE_FILE" up -d --no-deps backend # 헬스체크 대기 log_info "백엔드 헬스체크 대기 중..." sleep 30 # Nginx 업데이트 (필요시) if git diff --name-only "$CURRENT_COMMIT" "$NEW_COMMIT" | grep -E "(nginx|frontend)" > /dev/null; then docker-compose -f "$COMPOSE_FILE" build --no-cache nginx docker-compose -f "$COMPOSE_FILE" up -d --no-deps nginx fi else log_info "설정 파일만 업데이트 - 재시작 중..." docker-compose -f "$COMPOSE_FILE" restart backend nginx fi # 서비스 상태 확인 sleep 10 # 헬스체크 HEALTH_CHECK_FAILED=false # 백엔드 헬스체크 if ! curl -f http://localhost:24102/health > /dev/null 2>&1; then log_error "백엔드 헬스체크 실패" HEALTH_CHECK_FAILED=true fi # 프론트엔드 헬스체크 if ! curl -f http://localhost:24100/ > /dev/null 2>&1; then log_error "프론트엔드 헬스체크 실패" HEALTH_CHECK_FAILED=true fi # 헬스체크 실패 시 롤백 if [ "$HEALTH_CHECK_FAILED" = true ]; then log_error "헬스체크 실패 - 자동 롤백 실행" # 이전 커밋으로 롤백 git reset --hard "$CURRENT_COMMIT" # 컨테이너 롤백 docker-compose -f "$COMPOSE_FILE" down docker-compose -f "$COMPOSE_FILE" up -d --build log_error "업데이트 실패 - 이전 버전으로 롤백됨" echo "$(date '+%Y-%m-%d %H:%M:%S') - 업데이트 실패 (롤백): $NEW_COMMIT -> $CURRENT_COMMIT" >> "$UPDATE_LOG" exit 1 fi log_success "서비스 업데이트 완료" else log_info "컨테이너가 실행 중이지 않아 서비스 업데이트를 건너뜁니다" fi # 데이터베이스 마이그레이션 확인 log_info "🗄️ 데이터베이스 마이그레이션 확인 중..." if git diff --name-only "$CURRENT_COMMIT" "$NEW_COMMIT" | grep -E "(migrations|models)" > /dev/null; then log_warning "데이터베이스 스키마 변경 감지" if [ "$CONTAINERS_RUNNING" = true ]; then log_info "마이그레이션 실행 중..." docker-compose -f "$COMPOSE_FILE" exec -T backend python -m alembic upgrade head || true log_success "마이그레이션 완료" else log_warning "컨테이너가 실행 중이지 않아 마이그레이션을 건너뜁니다" fi fi # 업데이트 완료 log_success "🎉 업데이트 완료!" echo "" echo "=== 업데이트 정보 ===" echo "이전 커밋: ${CURRENT_COMMIT:0:8}" echo "새 커밋: ${NEW_COMMIT:0:8}" echo "업데이트된 커밋 수: $COMMITS_BEHIND" echo "백업 위치: $BACKUP_DIR/*_${BACKUP_NAME}.*" echo "" # 변경사항 요약 echo "=== 주요 변경사항 ===" git log --oneline "$CURRENT_COMMIT".."$NEW_COMMIT" | head -5 echo "" echo "=== 서비스 상태 ===" if [ "$CONTAINERS_RUNNING" = true ]; then docker-compose -f "$COMPOSE_FILE" ps echo "" echo "🌐 웹 인터페이스: http://localhost:24100" echo "🔧 API 문서: http://localhost:24102/docs" fi # 성공 로그 기록 echo "$(date '+%Y-%m-%d %H:%M:%S') - 업데이트 성공: $CURRENT_COMMIT -> $NEW_COMMIT" >> "$UPDATE_LOG" # 정리 작업 log_info "🧹 정리 작업 중..." # 오래된 백업 파일 정리 (30일 이상) find "$BACKUP_DIR" -name "pre_update_*" -mtime +30 -delete 2>/dev/null || true # Docker 이미지 정리 docker system prune -f > /dev/null 2>&1 || true log_success "업데이트 프로세스 완료" # 모니터링 실행 제안 echo "" echo "💡 업데이트 후 시스템 상태를 확인하려면:" echo " ./scripts/monitor-synology.sh" echo "" echo "🔙 문제가 있으면 롤백하려면:" echo " ./scripts/update-synology.sh rollback"