#!/bin/bash # 인페인팅 서버 시작 스크립트 # Jetson Xavier와 x86 시스템을 모두 지원합니다. # Usage: ./start_server.sh [options] set -e # 색상 코드 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 로그 함수들 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_ROOT="$(dirname "$SCRIPT_DIR")" MAIN_SERVER_PORT=8008 MONITORING_PORT=8888 LOG_DIR="$PROJECT_ROOT/logs" # 가상환경 경로 자동 감지 detect_venv_path() { local possible_paths=( "$PROJECT_ROOT/" # 일반적인 경로 "$PROJECT_ROOT/venv" # 일반적인 venv 경로 "$PROJECT_ROOT/.venv" # 숨김 venv 경로 "$PROJECT_ROOT/env" # env 경로 "$PROJECT_ROOT/.env" # 숨김 env 경로 "$PROJECT_ROOT" # 프로젝트 루트 (Jetson 방식) ) for path in "${possible_paths[@]}"; do if [ -f "$path/bin/python" ] || [ -f "$path/bin/python3" ]; then VENV_PATH="$path" log_info "가상환경 경로 감지: $VENV_PATH" return 0 fi done # 현재 활성화된 가상환경 확인 if [ -n "$VIRTUAL_ENV" ]; then VENV_PATH="$VIRTUAL_ENV" log_info "활성화된 가상환경 사용: $VENV_PATH" return 0 fi # 가상환경을 찾지 못한 경우 시스템별 기본값 사용 if [ "$(uname -m)" = "aarch64" ] && uname -a | grep -q "tegra"; then VENV_PATH="$PROJECT_ROOT" log_warning "가상환경을 찾을 수 없어 Jetson 기본값 사용: $VENV_PATH" else VENV_PATH="$PROJECT_ROOT/venv" log_warning "가상환경을 찾을 수 없어 x86 기본값 사용: $VENV_PATH" fi } # 시스템 감지 detect_system() { if [ "$(uname -m)" = "aarch64" ] && uname -a | grep -q "tegra"; then SYSTEM_TYPE="jetson" log_info "🚀 Jetson Xavier (ARM64) 모드로 시작합니다" # Jetson 전용 설정 WORKERS=1 MAX_WORKERS=4 MIN_WORKERS=1 VRAM_THRESHOLD_HIGH=0.7 VRAM_THRESHOLD_LOW=0.3 VRAM_CHECK_INTERVAL=20 MAX_FILE_SIZE=25 elif [ "$(uname -m)" = "x86_64" ]; then SYSTEM_TYPE="x86" log_info "💻 x86_64 모드로 시작합니다" # x86 전용 설정 (RTX 3060 12GB 최적화) WORKERS=4 MAX_WORKERS=12 MIN_WORKERS=4 VRAM_THRESHOLD_HIGH=0.85 VRAM_THRESHOLD_LOW=0.25 VRAM_CHECK_INTERVAL=20 MAX_FILE_SIZE=100 else log_error "지원되지 않는 시스템 아키텍처: $(uname -m)" exit 1 fi } # 옵션 파싱 PRODUCTION=false MONITORING_ENABLED=true WORKERS=1 GPU_DEVICE=0 JETSON_OPTIMIZE=false while [[ $# -gt 0 ]]; do case $1 in -p|--production) PRODUCTION=true shift ;; --no-monitoring) MONITORING_ENABLED=false shift ;; -w|--workers) WORKERS="$2" shift 2 ;; -g|--gpu) GPU_DEVICE="$2" shift 2 ;; --jetson-optimize) JETSON_OPTIMIZE=true shift ;; -h|--help) echo "Usage: $0 [options]" echo "Options:" echo " -p, --production 프로덕션 모드로 실행" echo " --no-monitoring 모니터링 대시보드 비활성화" echo " -w, --workers NUM 워커 수 설정 (기본값: 시스템별 자동)" echo " -g, --gpu DEVICE GPU 디바이스 ID (기본값: 0)" echo " --jetson-optimize Jetson 최적화 설정 (Jetson 전용)" echo " -h, --help 이 도움말 표시" exit 0 ;; *) log_error "알 수 없는 옵션: $1" exit 1 ;; esac done # 환경 확인 check_environment() { log_info "환경 확인 중..." # 프로젝트 디렉토리 확인 if [ ! -d "$PROJECT_ROOT" ]; then log_error "프로젝트 디렉토리를 찾을 수 없습니다: $PROJECT_ROOT" exit 1 fi # 가상환경 확인 log_info "가상환경 경로 확인: $VENV_PATH" if [ ! -f "$VENV_PATH/bin/activate" ]; then log_error "가상환경을 찾을 수 없습니다: $VENV_PATH" exit 1 fi # GPU 확인 (시스템별) if [ "$SYSTEM_TYPE" = "jetson" ]; then log_info "Jetson Xavier GPU 확인 중..." # Jetson 전용 확인 방법들 jetson_gpu_checks=0 # 1. tegrastats 확인 if command -v tegrastats &> /dev/null; then log_info "tegrastats 사용 가능" jetson_gpu_checks=$((jetson_gpu_checks + 1)) else log_warning "tegrastats를 찾을 수 없습니다" fi # 2. nvpmodel 확인 if command -v nvpmodel &> /dev/null; then log_info "nvpmodel 사용 가능" jetson_gpu_checks=$((jetson_gpu_checks + 1)) else log_warning "nvpmodel을 찾을 수 없습니다" fi # 3. GPU 디바이스 확인 (Jetson 전용 경로들) gpu_detected=false # Jetson GPU 클래스 확인 if [ -d "/sys/class/nvidia-gpu" ]; then log_info "Jetson GPU 클래스 감지됨: /sys/class/nvidia-gpu" gpu_detected=true fi # Jetson GPU 디바이스 확인 if [ -d "/sys/devices/platform/*/nvidia-gpu" ]; then log_info "Jetson GPU 디바이스 감지됨" gpu_detected=true fi # GV11B GPU 확인 (Jetson Xavier) if [ -d "/sys/firmware/devicetree/base/gv11b" ]; then log_info "GV11B GPU (Jetson Xavier) 감지됨" gpu_detected=true fi # 디버그 GPU 경로 확인 (권한이 있는 경우) if [ -r "/sys/kernel/debug/gpu" ]; then log_info "GPU 디버그 경로 접근 가능: /sys/kernel/debug/gpu" gpu_detected=true fi if [ "$gpu_detected" = true ]; then log_info "GPU 디바이스 감지됨" jetson_gpu_checks=$((jetson_gpu_checks + 1)) else log_warning "GPU 디바이스를 찾을 수 없습니다 (권한 문제일 수 있음)" log_info "sudo 권한으로 실행하거나 시스템을 재부팅해보세요" fi # 4. CUDA 확인 if command -v nvcc &> /dev/null; then log_info "CUDA 컴파일러 사용 가능" jetson_gpu_checks=$((jetson_gpu_checks + 1)) else log_warning "CUDA 컴파일러를 찾을 수 없습니다" fi if [ $jetson_gpu_checks -ge 2 ]; then log_success "Jetson Xavier GPU 확인 완료 ($jetson_gpu_checks/4 체크 통과)" # Jetson 정보 표시 (에러 방지) if command -v tegrastats &> /dev/null; then log_info "Jetson 시스템 정보:" tegrastats 2>/dev/null | head -5 || log_warning "tegrastats 실행 중 오류 발생" fi if command -v nvpmodel &> /dev/null; then log_info "Jetson 전력 모드:" nvpmodel -q 2>/dev/null || log_warning "nvpmodel 실행 중 오류 발생" fi else log_warning "Jetson Xavier GPU 확인 부분 실패 ($jetson_gpu_checks/4 체크 통과)" fi else # x86 시스템용 기존 확인 방법 if ! command -v nvidia-smi &> /dev/null; then log_warning "nvidia-smi를 찾을 수 없습니다. GPU 기능이 제한될 수 있습니다." else log_info "GPU 정보:" nvidia-smi --query-gpu=name,memory.total,memory.used --format=csv,noheader fi fi # 로그 디렉토리 생성 mkdir -p "$LOG_DIR" log_success "환경 확인 완료" } # 가상환경 활성화 activate_venv() { log_info "가상환경 활성화 중..." cd "$PROJECT_ROOT" source "$VENV_PATH/bin/activate" # Python 버전 확인 PYTHON_VERSION=$(python --version 2>&1) log_info "Python 버전: $PYTHON_VERSION" log_success "가상환경 활성화 완료" } # 포트 확인 및 기존 서버 정리 check_ports() { log_info "포트 사용 상태 확인 중..." # 메인 서버 포트 확인 if lsof -Pi :$MAIN_SERVER_PORT -sTCP:LISTEN -t >/dev/null; then log_warning "메인 서버 포트 $MAIN_SERVER_PORT가 이미 사용 중입니다" log_info "기존 서버를 중지하고 새로 시작합니다..." # 기존 서버 중지 pkill -f "uvicorn.*main:app" || true pkill -f "gunicorn.*main:app" || true pkill -f "python.*main.py" || true # 포트를 사용하는 프로세스 강제 종료 lsof -ti:$MAIN_SERVER_PORT | xargs -r kill -9 sleep 3 # 포트가 여전히 사용 중인지 재확인 if lsof -Pi :$MAIN_SERVER_PORT -sTCP:LISTEN -t >/dev/null; then log_error "포트 $MAIN_SERVER_PORT를 해제할 수 없습니다" lsof -Pi :$MAIN_SERVER_PORT -sTCP:LISTEN exit 1 fi log_success "기존 메인 서버 중지 완료" fi # 모니터링 서버 포트 확인 if [ "$MONITORING_ENABLED" = true ] && lsof -Pi :$MONITORING_PORT -sTCP:LISTEN -t >/dev/null; then log_warning "모니터링 포트 $MONITORING_PORT가 이미 사용 중입니다" log_info "기존 모니터링 서버를 중지하고 새로 시작합니다..." # 기존 모니터링 서버 중지 pkill -f "dashboard:monitor_app" || true pkill -f "monitoring.dashboard" || true # 포트를 사용하는 프로세스 강제 종료 lsof -ti:$MONITORING_PORT | xargs -r kill -9 sleep 3 # 포트가 여전히 사용 중인지 재확인 if lsof -Pi :$MONITORING_PORT -sTCP:LISTEN -t >/dev/null; then log_error "포트 $MONITORING_PORT를 해제할 수 없습니다" lsof -Pi :$MONITORING_PORT -sTCP:LISTEN exit 1 fi log_success "기존 모니터링 서버 중지 완료" fi log_success "포트 확인 완료" } # 의존성 확인 check_dependencies() { log_info "의존성 확인 중..." # requirements.txt가 있는지 확인 if [ -f "$PROJECT_ROOT/requirements.txt" ]; then log_info "필수 패키지 설치 확인 중..." # 이미 설치된 패키지들 확인 if python -c "import fastapi, uvicorn, torch, cv2, PIL" 2>/dev/null; then log_success "필수 패키지들이 이미 설치되어 있습니다" else log_warning "일부 패키지가 누락되었습니다. 수동으로 설치가 필요할 수 있습니다" fi else log_warning "requirements.txt를 찾을 수 없습니다" fi } # Jetson 최적화 setup_jetson_optimization() { if [ "$SYSTEM_TYPE" != "jetson" ] || [ "$JETSON_OPTIMIZE" != true ]; then return 0 fi log_info "🚀 Jetson Xavier 최적화 설정 중..." # 전력 모드 설정 if command -v nvpmodel &> /dev/null; then log_info "전력 모드를 MAXN으로 설정 중..." sudo nvpmodel -m 0 2>/dev/null || log_warning "MAXN 모드 설정 실패" sudo nvpmodel -q 2>/dev/null || log_warning "전력 모드 확인 실패" else log_warning "nvpmodel을 찾을 수 없습니다" fi # 팬 제어 설정 if [ -f "/sys/devices/pwm-fan/target_pwm" ]; then log_info "팬 제어 활성화 중..." echo 128 | sudo tee /sys/devices/pwm-fan/target_pwm > /dev/null fi # GPU 클럭 설정 if [ -f "/sys/kernel/debug/clk/gpcclk/clk_rate" ]; then log_info "GPU 클럭 최적화 중..." echo 1200000000 | sudo tee /sys/kernel/debug/clk/gpcclk/clk_rate > /dev/null fi # 메모리 클럭 설정 if [ -f "/sys/kernel/debug/clk/emc/clk_rate" ]; then log_info "메모리 클럭 최적화 중..." echo 1600000000 | sudo tee /sys/kernel/debug/clk/emc/clk_rate > /dev/null fi log_success "Jetson 최적화 설정 완료" } # 환경 변수 설정 setup_environment() { log_info "환경 변수 설정 중..." # CUDA 설정 export CUDA_VISIBLE_DEVICES=$GPU_DEVICE export CUDA_DEVICE_ORDER=PCI_BUS_ID # PyTorch 설정 export TORCH_CUDA_ARCH_LIST="6.0;6.1;7.0;7.5;8.0;8.6" # Jetson 전용 설정 if [ "$SYSTEM_TYPE" = "jetson" ]; then export CUDA_LAUNCH_BLOCKING=1 export CUDA_CACHE_DISABLE=0 export CUDA_CACHE_PATH="/tmp/cuda_cache" # Jetson 메모리 최적화 export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128 fi # TensorRT 설정 (있는 경우) if [ -d "/usr/local/tensorrt" ]; then export LD_LIBRARY_PATH=/usr/local/tensorrt/lib:$LD_LIBRARY_PATH fi # 프로덕션 설정 if [ "$PRODUCTION" = true ]; then export PYTHONOPTIMIZE=1 export PYTHONDONTWRITEBYTECODE=1 fi log_success "환경 변수 설정 완료" } # 서버 시작 start_servers() { log_info "서버 시작 중..." # 메인 서버 시작 log_info "메인 인페인팅 서버 시작 (포트: $MAIN_SERVER_PORT, 워커: $WORKERS)..." if [ "$PRODUCTION" = true ]; then # 프로덕션 모드: Gunicorn 사용 gunicorn main:app \ --bind 0.0.0.0:$MAIN_SERVER_PORT \ --workers $WORKERS \ --worker-class uvicorn.workers.UvicornWorker \ --max-requests 1000 \ --max-requests-jitter 50 \ --preload \ --access-logfile "$LOG_DIR/access.log" \ --error-logfile "$LOG_DIR/error.log" \ --log-level info \ --daemon \ --pid "$LOG_DIR/main_server.pid" else # 개발 모드: Uvicorn 사용 (단일 프로세스로 실행하여 lifespan 함수가 정상 작동하도록 함) nohup python -m uvicorn main:app \ --host 0.0.0.0 \ --port $MAIN_SERVER_PORT \ --log-level info \ --access-log \ > "$LOG_DIR/main_server.log" 2>&1 & echo $! > "$LOG_DIR/main_server.pid" fi # 메인 서버 시작 대기 (모델 로딩 시간 고려) log_info "메인 서버 초기화 대기 중... (최대 120초)" local timeout=120 local elapsed=0 local interval=5 while [ $elapsed -lt $timeout ]; do sleep $interval elapsed=$((elapsed + interval)) # 올바른 헬스체크 엔드포인트 사용 if curl -s "http://localhost:$MAIN_SERVER_PORT/api/v1/health" > /dev/null 2>&1; then log_success "메인 서버 시작 완료 (PID: $(cat $LOG_DIR/main_server.pid)) - ${elapsed}초 소요" break fi # 진행 상황 로깅 (더 자주) if [ $((elapsed % 10)) -eq 0 ]; then log_info "메인 서버 초기화 중... (${elapsed}/${timeout}초) - 모델 로딩 진행 중" fi done # 최종 확인 if ! curl -s "http://localhost:$MAIN_SERVER_PORT/api/v1/health" > /dev/null 2>&1; then log_error "메인 서버 시작 실패 (${timeout}초 타임아웃)" log_info "모델 로딩이 진행 중일 수 있습니다. 로그를 확인하세요:" log_info " tail -f $LOG_DIR/main_server.log" log_info "서버 프로세스가 실행 중인지 확인하세요:" log_info " ps aux | grep uvicorn" exit 1 fi # 모니터링 서버 시작 (활성화된 경우) if [ "$MONITORING_ENABLED" = true ]; then log_info "모니터링 대시보드 시작 (포트: $MONITORING_PORT)..." # Python 경로 설정으로 import 문제 해결 cd "$PROJECT_ROOT" PYTHONPATH="$PROJECT_ROOT" nohup python -c " from app.monitoring.dashboard import monitor_app import uvicorn uvicorn.run(monitor_app, host='0.0.0.0', port=$MONITORING_PORT, log_level='info') " > "$LOG_DIR/monitoring.log" 2>&1 & echo $! > "$LOG_DIR/monitoring.pid" sleep 5 # 모니터링 서버 상태 확인 if curl -s "http://localhost:$MONITORING_PORT/api/simple" > /dev/null; then log_success "모니터링 대시보드 시작 완료 (PID: $(cat $LOG_DIR/monitoring.pid))" log_info "모니터링 URL: http://localhost:$MONITORING_PORT" else log_warning "모니터링 대시보드 시작 실패 - 로그 확인: $LOG_DIR/monitoring.log" fi fi } # 상태 정보 출력 print_status() { echo "" echo "==========================================" echo "🚀 인페인팅 서버 시작 완료!" echo "==========================================" echo "시스템 타입: $SYSTEM_TYPE" echo "메인 서버: http://localhost:$MAIN_SERVER_PORT" echo "API 문서: http://localhost:$MAIN_SERVER_PORT/docs" echo "헬스 체크: http://localhost:$MAIN_SERVER_PORT/health" if [ "$MONITORING_ENABLED" = true ]; then echo "모니터링: http://localhost:$MONITORING_PORT" fi echo "" echo "로그 디렉토리: $LOG_DIR" echo "GPU 디바이스: $GPU_DEVICE" echo "워커 수: $WORKERS" echo "프로덕션 모드: $PRODUCTION" if [ "$SYSTEM_TYPE" = "jetson" ]; then echo "" echo "🚀 Jetson Xavier 최적화:" echo " - 전력 모드: MAXN" echo " - GPU 클럭: 1200MHz" echo " - 메모리 클럭: 1600MHz" echo " - 팬 제어: 활성화" echo " - VRAM 임계값: 70%/30%" echo " - 파일 크기 제한: 25MB" fi echo "" echo "서버 중지: ./scripts/stop_server.sh" echo "상태 확인: ./scripts/status.sh" if [ "$SYSTEM_TYPE" = "jetson" ]; then echo "Jetson 모니터링: jtop" echo "전력 모드 확인: nvpmodel -q" fi echo "==========================================" } # 메인 실행 main() { log_info "인페인팅 서버 시작 스크립트 실행" detect_system detect_venv_path check_environment activate_venv check_ports check_dependencies setup_jetson_optimization setup_environment start_servers print_status log_success "모든 서버가 성공적으로 시작되었습니다!" } # 스크립트 실행 main "$@"